在
细节巨多的 DP。
首先有一个较为显然的
然后这个东西实际上是可以通过类似前缀和的东西转移的,但是是类似对角线前缀和的,比较复杂细节巨多,所以这里参考以下机房大佬 @sssmzy 的做法。
考虑将状态修改为
这个时候考虑两种可能性,对于某次枚举的位置
考虑对于
具体来说,维护一个
转移的意义即为在
于是每次处理完 DP 后清空并重新维护
最终复杂度为
xxxxxxxxxx
811
2
3
4
5
6
7
8
9
10
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
22
23
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 >= dis
48 ?
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)) % MOD
52 : 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 初稿