版权声明:希望大家转载的时候把公式转载好一点QAQ,我就公式打得很辛苦了... https://blog.csdn.net/Myriad_Dreamin/article/details/85037516
有一个长度为
n的的数列,
ai的值域只有
k个元素。
一个数列有一些数字已经填上。现在要求数列连续的数字长度不能超过
l,问所有不同的数列的个数有多少个。
1.考虑所有的数字都没填上。设
dp[i][j][s]为第
i个位置填入第
j种颜色且已经有连续的
s个数字的方案数。显然:
那么:
dp[i][j][s]=dp[i−1][j][s−1]−[s⩾l−1](p=1∑∞(t=1∑kdp[i−l+1][t][p]−dp[i−l+1][j][p])),2⩽s⩽l−1,dp[i][j][s]=1⩽t⩽k,j̸=t∑p=1∑∞dp[i−1][t][p],s=1dp[i][j][s]=0,s⩾l.
求和得:
p=1∑sdp[i][j][p]=p=1∑∞t=1∑kdp[i−1][j][p]−[s⩾l−1](p=1∑∞t=1∑kdp[i−l+1][t][p]−p=1∑∞dp[i−l+1][j][p])
因为具有规整性,并且考虑到
dp[i][j][s]=dp[i−1][j][s−1],
所以令
ava[i][j]=p=1∑∞dp[i][j][p],sum[i]=i=1∑kava[i][j],得:
ava[i][j]=sum[i−1]−[maxavalenj⩾l−1](sum[i−l+1]−ava[i−l+1]),i=1,2,…,n
其中
maxavalenj是指当前可能达到的最大连续后缀长度。
2.考虑有的数字已经填上。显然这时候,如果
j=a[i],则可以继续转移,但是只有一种可能。如果
j̸=a[i],也可以继续转移,但是
maxavalenj被隔断,所以重新计算。
#include <cstdio>
#include <iostream>
const int N=100005,K=105;
const long long mod=998244353LL;
int a[N];
long long dp[N],ava[N][K],len[K],bad[K];
int main(){
int n,k,l;
scanf("%d%d%d",&n,&k,&l);l--;
if(!l){
puts("0");
return 0;
}
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
dp[0]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=k;j++){
if(a[i]==j||a[i]==-1){
ava[i][j]=(dp[i-1]+mod-bad[j])%mod;
len[j]++;
if(len[j]>=l){
bad[j]=(dp[i-l]+mod-ava[i-l][j])%mod;
}
dp[i]+=ava[i][j];
if(dp[i]>=mod)dp[i]-=mod;
}else{
len[j]=bad[j]=0;
}
}
}
printf("%I64d\n",dp[n]);
}