洛谷P5404 [CTS2019] 重复

先转化为总方案数减去每个子串都大于等于 (S) 的方案数。

(T) 为所统计的字符串。对 (S) 构建 (kmp) 自动机,自动机上的每个节点只保留转移到根节点和转移到 ( ext{next}) 链上字符最大的节点两种转移路径,因为如果 (T) 在匹配时不走最大的字符,(T) 在重复后,一定会出现小于 (S) 的子串。

(p)(T) 重复无限次后对应的节点,那么节点 (p) 一定满足再加入一个 (T) 后,其又回到了节点 (p),即出现了一个环,该环可能重复经过节点。

那么考虑 (DP),统计自动机上一个节点走 (m) 步后回到其本身的方案数,复杂度为 (O(n^2m)),要考虑优化。

发现环可以分为经过根节点和不经过根节点的两种。不经过根节点可以直接判断,经过根节点可以枚举起始节点和第一次转移到根节点前走的距离,预处理出 (f_{i,x}),为从根节点走了 (i) 步到节点 (x) 的方案数,通过预处理的信息即可统计答案。

统计答案时可以快速算出第一次转移到根节点前的方案数,因为自动机一直不经过根节点前走的路径是唯一的,即一直匹配。

复杂度为 (O(nm))

#include<bits/stdc++.h>
#define maxn 2010
#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 m,n,pos;
ll tot=1,ans;
int nxt[maxn],mx[maxn],ch[maxn][30];
ll f[maxn][maxn];
char s[maxn];
int main()
{
    read(m),scanf("%s",s+1),n=strlen(s+1);
    for(int i=2;i<=n;++i)
    {
        while(pos&&s[i]!=s[pos+1]) pos=nxt[pos];
        if(s[i]==s[pos+1]) pos++;
        nxt[i]=pos;
    }
    for(int x=0;x<=n;++x)
    {
        mx[x]=max(mx[nxt[x]],s[x+1]-'a');
        for(int i=0;i<mx[x];++i) ch[x][i]=-1;
        for(int i=mx[x];i<26;++i)
        {
            if(s[x+1]-'a'==i) ch[x][i]=x+1;
            else
            {
                int y=nxt[x];
                while(ch[y][i]==-1) y=nxt[y];
                ch[x][i]=ch[y][i];
            }
        }
    }
    f[0][0]=1;
    for(int i=0;i<m;++i)
    {
        tot=tot*26%p;
        for(int x=0;x<=n;++x)
        {
            if(!f[i][x]) continue;
            for(int c=mx[x];c<26;++c)
                f[i+1][ch[x][c]]=(f[i+1][ch[x][c]]+f[i][x])%p;
        }
    }
    for(int x=0;x<=n;++x)
    {
        int y=x;
        for(int i=0;i<m;++i)
            ans=(ans+(25-mx[y])*f[m-i-1][x]%p)%p,y=ch[y][mx[y]];
        if(y==x) ans++;
    }
    printf("%lld",(tot-ans+p)%p);
    return 0;
}
原文地址:https://www.cnblogs.com/lhm-/p/13779561.html