1 条题解
-
0
看完题,注意到 。加上求方案数,大概率就是 dp 了。
一开始想的是 表示前 个数,第 个数是 ,且已经连续了 个数的方案数。但是这样就是 的状态了,会炸掉。
于是我们考虑保留其中最重要的两维,即 和 ,并且考虑枚举 ,因为正常情况下,时间复杂度会比较好优化。
设 表示前 个数,第 个数是 的方案数。转移如下。
$$f_{i,j} = \sum_{k=i-j \wedge [\forall p \in [k,i),p = j \vee p = -1]}^{i-1}\sum_{col \not = j} f_{k,col}$$这样子我们就可以考虑前缀和优化了。首先预处理 的可行范围,这个可以 预处理。
考虑记 表示 。这样子就可以 的转移了。
初始化因为没有数字,为了防止影响后面转移,我们设 号位置数字是 。这样子 。
#include <bits/stdc++.h> using namespace std; #define il inline #define N 5005 il int rd(){ int s = 0, w = 1; char ch = getchar(); for (;ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') w = -1; for (;ch >= '0' && ch <= '9'; ch = getchar()) s = ((s << 1) + (s << 3) + ch - '0'); return s * w; }const int P = 998244353; int n, a[N], pre[N][N], f[N][N], sum[N], s[N][N]; int main(){ n = rd(); for (int i = 1; i <= n; i++){ a[i] = rd(); for (int j = 1; j <= n; j++) if (a[i] == j || a[i] == -1) pre[i][j] = pre[i - 1][j] + 1; }f[0][0] = sum[0] = 1; for (int j = 1; j <= n; j++) s[0][j] = 1; for (int i = 1; i <= n; i++){ for (int j = 1; j <= n; j++) if (a[i] == j || a[i] == -1){ int lst = i - min(pre[i][j], j); f[i][j] = (s[i - 1][j] - (lst ? s[lst - 1][j] : 0) + P) % P, sum[i] = (sum[i] + f[i][j]) % P; }for (int j = 1; j <= n; j++) s[i][j] = (s[i - 1][j] + (sum[i] - f[i][j] + P) % P) % P; }printf ("%lld\n", sum[n]); return 0; }
- 1
信息
- ID
- 11517
- 时间
- 2000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者