CF1093F Vasya and Array
这个题还是有点东西的啊。
现场并没有过掉qwq
发现颜色种类很少,考虑n*k的dp。
dp[i][j]表示第i位填j的方案数。
转移的时候,枚举这个颜色段向左扩展了多长。
因为受到len的限制,它最多只能扩展到i-len+2。
这里还要预处理一下g[i][j]表示这个颜色向左最多能扩展到什么位置。
这个是为了计算颜色对扩展位置的限制,综上,t=max(g[i][j],i-len+2)。
考虑在t右边的(包括t)的位置怎么转移,发现可以把一个-1作为划分点。
这个位置以后全部与j相同。
此时这个位置只需要填任意一个与j不同的颜色即可。
这个式子显然可以用前缀和优化一波。
维护一下总方案数的前缀和,维护一下每种颜色的前缀和,转移时作差即可。
此外,还有一种情况需要注意,t-1也是可以进行转移,也是只需要填一个与j不同的颜色即可。
注意处理一下t-1为0的情况。
#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#define K 105
#define N 100050
#define L 100000
#define eps 1e-7
#define inf 1e9+7
#define ll long long
using namespace std;
inline ll read()
{
char ch=0;
ll x=0,flag=1;
while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*flag;
}
const ll mo=998244353;
ll a[N],s[N],f[N][K],g[N][K],dp[N][K];
int main()
{
ll n=read(),k=read(),len=read();
if(len==1){printf("0");return 0;}
for(ll i=1;i<=n;i++)a[i]=read();
for(ll i=1;i<=n;i++)for(ll j=1;j<=k;j++)
if(a[i-1]==-1||a[i-1]==j)g[i][j]=g[i-1][j];
else g[i][j]=i;
s[0]=1;
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<=k;j++)if(a[i]==-1||a[i]==j)
{
ll t=max(g[i][j],i-len+2);
dp[i][j]=((s[i-1]-s[t-1])-(f[i-1][j]-f[t-1][j]))%mo;
dp[i][j]=(dp[i][j]+s[t-1]-(t==1?0:s[t-2])-dp[t-1][j])%mo;
}
s[i]=s[i-1];
for(ll j=1;j<=k;j++)
{
s[i]=(s[i]+dp[i][j])%mo;
f[i][j]=(f[i-1][j]+dp[i][j])%mo;
}
}
ll ans=0;
for(ll i=1;i<=k;i++)ans=(ans+dp[n][i])%mo;
printf("%lld",(ans+mo)%mo);
return 0;
}