在
细节巨多的 DP。
首先有一个较为显然的
然后这个东西实际上是可以通过类似前缀和的东西转移的,但是是类似对角线前缀和的,比较复杂细节巨多,所以这里参考以下机房大佬 @sssmzy 的做法。
考虑将状态修改为
这个时候考虑两种可能性,对于某次枚举的位置
考虑对于
具体来说,维护一个
转移的意义即为在
于是每次处理完 DP 后清空并重新维护
最终复杂度为
xxxxxxxxxx81123
45678910
11using namespace std;12
13mt19937 rnd(random_device{}());14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}15bool rnddd(int x){return rndd(1, 100) <= x;}16
17typedef unsigned int uint;18typedef unsigned long long unll;19typedef long long ll;20typedef long double ld;21
2223
24template < typename T = int >25inline T read(void);26
27int N, D;28int P[110], Q[110];29ll dp[2100][1100];30ll sum[2100][1100];31ll sum2[2100][1100];32ll ans(0);33
34int main(){35 N = read(), D = read();36 for(int i = 1; i <= N; ++i)P[i] = read();37 for(int i = 1; i <= N; ++i)Q[i] = read();38 dp[0][0] = 1;39 for(int j = 0; j <= D * 2; ++j)40 for(int k = 0; k <= D; ++k)41 sum[j][k] = ((k - 1 >= 0 ? sum[j][k - 1] : 0) + dp[j][k]) % MOD,42 sum2[j][k] = ((j - 2 >= 0 && k - 1 >= 0 ? sum2[j - 2][k - 1] : 0) + dp[j][k]) % MOD;43 for(int i = 1; i <= N; ++i){44 for(int j = 0; j <= D * 2; ++j)45 for(int k = 0; k <= D; ++k){46 int dis = abs(P[i] - Q[i]);47 dp[j][k] = j >= dis48 ?49 ((sum[j - dis][k] - (k - dis - 1 >= 0 ? sum[j - dis][k - dis - 1] : 0) + MOD) % MOD +50 (j - dis - 2 >= 0 && k - 1 >= 0 ? sum2[j - dis - 2][k - 1] % MOD : 0) +51 (j - dis - 2 >= 0 && k - dis - 1 >= 0 ? sum2[j - dis - 2][k - dis - 1] % MOD : 0)) % MOD52 : 0;53 }54 memset(sum, 0, sizeof sum), memset(sum2, 0, sizeof sum2);55 for(int j = 0; j <= D * 2; ++j)56 for(int k = 0; k <= D; ++k)57 sum[j][k] = ((k - 1 >= 0 ? sum[j][k - 1] : 0) + dp[j][k]) % MOD,58 sum2[j][k] = ((j - 2 >= 0 && k - 1 >= 0 ? sum2[j - 2][k - 1] : 0) + dp[j][k]) % MOD;59 }60 for(int j = 0; j <= D * 2; ++j)for(int k = 0; k <= min(j, D); ++k)61 if(j - k <= D) (ans += dp[j][k]) %= MOD;62 printf("%lld\n", ans);63 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);64 return 0;65}66
67template < typename T >68inline T read(void){69 T ret(0);70 int flag(1);71 char c = getchar();72 while(c != '-' && !isdigit(c))c = getchar();73 if(c == '-')flag = -1, c = getchar();74 while(isdigit(c)){75 ret *= 10;76 ret += int(c - '0');77 c = getchar();78 }79 ret *= flag;80 return ret;81}update-2023_01_05 初稿