1. 程式人生 > 實用技巧 >題解 CF1093F 【Vasya and Array】

題解 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;
}