题目链接:洛谷
以后还是要多打CF,不然就会错过这些很好的思维题了。我dp学得还是太烂,要多总结。
首先$len=1$就直接输出0.
我们考虑$dp[i][j]$表示前$i$个数的答案,而且第$i$个数要选$j$,$ans[i]=sum_{j=1}^kdp[i][j]$
而且$del[j]$表示前$i$个数中,末尾的$j$刚好出现$len-1$次的好的数列,目的是为后面下一步dp作铺垫(雾)
$$dp[i][j]=ans[i-1]-del[j]$$
$$ans[i]+=dp[i][j]$$
$$del[j]=ans[i-len+1]-dp[i-len+1][j]$$
注意上面的先后顺序是不能改变的。
但是第三条方程必须要保证前面至少要有连续$len-1$个可能的$j$,否则就不行。这需要一个$cnt[]$数组来维护
U2FsdGVkX18i7uuFtRXRKp4L3/XpHCArvYcxfRh5nSDoA+n72JMYCjGy/WnhKn/F Cn+w2+0U2JWHEtAnfU8mxjc/R841pS9cOdnyf8OE28K1vI1RFtlJCsIKUoMfyYJg gKaptA14c9ysJFLbpKJ7KjCwHLy4s+fx0gE2joNiLvNFcSQzayv4Dx1w3dtaQbM9 TwBumGo4LA
1 #include<cstdio> 2 #define Rint register int 3 using namespace std; 4 typedef long long LL; 5 const int N = 100003, mod = 998244353; 6 int n, k, len, a[N], cnt[N], del[N], dp[N][103], ans[N]; 7 int main(){ 8 scanf("%d%d%d", &n, &k, &len); 9 if(len == 1){puts("0"); return 0;} 10 for(Rint i = 1;i <= n;i ++) scanf("%d", a + i); 11 ans[0] = 1; 12 for(Rint i = 1;i <= n;i ++) 13 for(Rint j = 1;j <= k;j ++) 14 if(a[i] == -1 || a[i] == j){ 15 dp[i][j] = (ans[i - 1] - del[j] + mod) % mod; 16 ++ cnt[j]; 17 if(cnt[j] >= len - 1) del[j] = (ans[i - len + 1] - dp[i - len + 1][j] + mod) % mod; 18 ans[i] = (ans[i] + dp[i][j]) % mod; 19 } else del[j] = cnt[j] = 0; 20 printf("%d ", ans[n]); 21 }