題解 CF1093F 【Vasya and Array】
阿新 • • 發佈:2020-08-17
考慮通過 \(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; }