题解 CF1093F 【Vasya and Array】
考虑通过 \(DP\) 来解决本题。设 \(f_{i,j}\) 为考虑了前 \(i\) 个位置且第 \(i\) 个位置为数字 \(j\) 的方案数,\(s_i\) 为 \(\sum\limits_{j=1}^k f_{i,j}\),\(l_{i,j}\) 为位置 \(i\) 往前都是数字 \(j\) 的最长长度,得:
\[\large f_{i,j}=
\begin{cases}
s_{i-1} &l_{i,j} < len\\
\\
s_{i-1}-s_{i-len}+f_{i-len,j} &l_{i,j} \geqslant len\\
\end{cases}
\]
\(l_{i,j} < len\) 时不可能出现不合法的情况,所以直接从 \(s_{i-1}\) 转移过来。
\(l_{i,j} \geqslant len\) 时转移过来的状态就会出现不合法的情况。考虑对于区间 \([i-len+1,i]\),若该区间都为 \(j\),就会出现不合法的情况,因为区间都为 \(j\) 只有一种情况,所以其方案数即为 \(s_{i-len}\)。但是这里是想把长度恰好为 \(len\) 且在 \(i\) 结尾的不合法情况减去,直接减去 \(s_{i-len}\) 会多减长度大于 \(len\) 的情况,所以还要加上 \(f_{i-len,j}\)。
#include<bits/stdc++.h>
#define maxn 100010
#define maxk 110
#define p 998244353
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,k,len;
ll a[maxn],f[maxn][maxk],s[maxn],l[maxn][maxk];
int main()
{
read(n),read(k),read(len);
for(int i=1;i<=n;++i) read(a[i]);
for(int i=1;i<=n;++i)
for(int j=1;j<=k;++j)
if(a[i]==j||a[i]==-1)
l[i][j]=l[i-1][j]+1;
s[0]=1;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=k;++j)
{
if(a[i]!=j&&a[i]!=-1) continue;
f[i][j]=s[i-1];
if(l[i][j]>=len) f[i][j]=((f[i][j]-s[i-len]+p)%p+f[i-len][j])%p;
s[i]=(s[i]+f[i][j])%p;
}
}
printf("%lld",s[n]);
return 0;
}