题解 CF1093F 【Vasya and Array】

XG_Zepto

2018-12-18 20:26:58

Solution

首发于 [个人博客](https://zepto.page/post/codeforces-1093f)。 ### 思路 我们可以使用 $DP$ 解决这个问题。令 $f_{i,j}$ 为考虑前 $i$ 个数,第 $i$ 个数为 $j$ 的合法方案数,$s_i$ 等于 $\sum f_{i,j}$。 那么,$f_{i,j}$ 一定从 $s_{i-1}$ 转移而来,如果 $a_j$ 恰好等于 $j$ 或者 $-1$ 的话。但是,直接转移会包含不合法的情况。我们考虑,一些状态不合法,当且仅当: 1. $i≥len$; 2. 子区间 $\{a_1,\cdots,a_i\}$ 中所有的元素都等于 $−1$ 或者 $j$。 发现,满足以上两个条件的状态数实际上就是 $s_{i-len}-f_{i-len,j}$。转移的时候删去即可。 ### 代码 ```cpp #include <bits/stdc++.h> #define md 998244353 #define maxn 100001 #define max(a,b) (a>b?a:b) #define maxk 101 int n,k,len,a[maxn]; int f[maxn][maxk],s[maxn],cnt[maxn][maxk]; void inc(int &a,int b){a=((a+b>=md)?a+b-md:a+b);} int main(){ scanf("%d%d%d",&n,&k,&len); for (register int i=1;i<=n;++i) scanf("%d",&a[i]); for (register int i=1;i<=n;++i) for (register int j=1;j<=k;++j) inc(cnt[i][j],cnt[i-1][j]+(a[i]==j||a[i]==-1)); for (register int i=1;i<=n;++i){ for (register int j=1;j<=k;++j){ if (!(a[i]==j||a[i]==-1)) continue; int add=1; if (i>1) add=s[i-1]; inc(f[i][j],add); bool ok=i>=len; int l=max(1,i-len+1); ok&=(cnt[i][j]-cnt[l-1][j]==len); if (!ok) continue; if (i==len) {inc(f[i][j],md-1);continue;} int sum=f[i-len][j]; inc(sum,md-s[i-len]); inc(f[i][j],sum); } for (register int j=1;j<=k;++j) inc(s[i],f[i][j]); } printf("%d\n",s[n]); } ```