zoukankan      html  css  js  c++  java
  • P5404 [CTS2019]重复 KMP自动机

    题意:

    戳这里

    分析:

    • 暴力

    暴力枚举,最小表示法判断,复杂度 ((26^m*m)) 期望得分 10pts

    • 正解

    转化要求,求不合法的串的个数

    我们只要保证构造的无限长串的任意长度为 |s| 的子串的字典序都大于 s ,那么这个串就是不合法的

    这样对于不合法串在 s 的 KMP自动机 上匹配的时候,只有两类转移边,一种是转移到根节点,一种是转移到 nxt​ 链上最大的节点

    我们记 (P(x)) 表示串 x 匹配的结束的位置,长度为无限大的串匹配结束的位置为 (P(t^{infty}))

    很显然对于 (P(t^{infty}+t)=P(t^{infty})) ,所以对于那些再匹配一个 (t) 后回到自己的点,就是 (P(t^{infty}))

    所以我们得到了一个方法,我们只需要找到一个节点,满足走 (|t|) 步之后可以回到自己,那么这条路径就是一种合法的 (t),枚举节点然后DP,复杂度 (O(n^2m))

    考虑怎么优化,我们发现环可以分为经过根节点和不经过根节点两种,不经过根节点的方案很好求,因为转移边固定,所以我们每次直接走不回到根节点的转移边,复杂度 (O(nm)) 然后我们考虑经过根节点,我们预处理出根节点走 (|t|) 步以内能到某一个节点的方案数,然后枚举从那一个节点回到根节点,复杂度 (O(nm))

    代码:

    #include<bits/stdc++.h>
    #define inl inline
    #define reg register
    
    using namespace std;
    
    namespace zzc
    {
        typedef long long ll;
        
        const int maxn = 2005;
        const ll mod = 998244353;
        ll ch[maxn][26],nxt[maxn],f[maxn][maxn],mx[maxn];
        ll n,cnt,sum=1,ans,len;
        char s[maxn];
    
        void work()
        {
            scanf("%lld",&n);for(reg ll i=1;i<=n;i++) sum=sum*26%mod;
            scanf("%s",s+1);len=strlen(s+1);
            nxt[0]=-1;mx[0]=0;
            for(reg ll i=1;i<=len;i++)
            {
                ll j=nxt[i-1];
                while(j!=-1&&s[j+1]!=s[i]) j=nxt[j];
                nxt[i]=j+1;
            }
            for(reg int i=0;i<=len;i++) for(reg int c=0;c<26;c++)
            {
                if(s[i+1]-'a'==c) ch[i][c]=i+1;
                else ch[i][c]=(i==0?0:ch[nxt[i]][c]);
                if(ch[i][c]) mx[i]=c;
            }
            f[0][0]=1;
            for(reg ll i=0;i<n;i++) for(reg ll j=0;j<=len;j++) for(reg ll c=mx[j];c<26;c++) f[i+1][ch[j][c]]=(f[i+1][ch[j][c]]+f[i][j])%mod;
            for(reg ll i=0;i<=len;i++)
            {
                ll now=i;
                for(reg ll j=0;j<n;j++)
                {
                    ans=(ans+1ll*(26-mx[now]-1)*f[n-j-1][i]%mod)%mod;
                    now=ch[now][mx[now]];
                    if(!now) break;
                }
                ans+=(now&&now==i);
            }
            printf("%lld
    ",(sum-ans+mod)%mod);
        }
    
    }
    
    int main()
    {
        zzc::work();
        return 0;
    }
    
  • 相关阅读:
    hihocoder #1333 : 平衡树·Splay2
    【bzoj1251】序列终结者 splay
    BZOJ 1588: [HNOI2002]营业额统计 双向链表 / splay / treap
    湖南省第十二届大学生计算机程序设计竞赛 F 地铁 多源多汇最短路
    湖南省第十二届大学生计算机程序设计竞赛 B 有向无环图 拓扑DP
    湖南省第十二届大学生计算机程序设计竞赛 G Parenthesis
    HDU 4251 The Famous ICPC Team Again 主席树
    Codeforces Round #369 (Div. 2) D. Directed Roads dfs求某个联通块的在环上的点的数量
    python main
    python显示灰度图
  • 原文地址:https://www.cnblogs.com/youth518/p/14465066.html
Copyright © 2011-2022 走看看