CF1093F Vasya and Array

题目链接:洛谷

以后还是要多打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 }
CF1093F
原文地址:https://www.cnblogs.com/AThousandMoons/p/10689163.html