• hdu5343 后缀自动机+dp


    给定两个串,分别截取字串X和Y,连接组成X+Y,求不同的X+Y的方案数。

    对于X+Y,如果重复的部分其实就是从同一个X+Y的某个地方断开弄成不同的X和Y,那么只要使得X和X+Y匹配得最长就行了。

    因此,对两个字符串分别建立后缀自动机A和B,在A中找字串X,当X的末尾不能接某个字符c时,在B中找以c为开头的所有字串。

    注意字串的是n^2个,所以不管怎样都不能以暴力遍历自动机的方式来统计,而由于SAM是DAG,所以实际上是在两个DAG上进行dp。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #define REP(i,a,b) for(int i=a;i<=b;i++)
    #define MS0(a) memset(a,0,sizeof(a))
    
    using namespace std;
    
    typedef unsigned long long ll;
    const int maxn=1000100;
    const int INF=1e9+10;
    
    char s[maxn],t[maxn];
    ll dp1[maxn],dp2[maxn];
    
    struct SAM
    {
        int ch[maxn][26];
        int pre[maxn],step[maxn];
        int last,tot;
        void init()
        {
            last=tot=0;
            memset(ch[0],-1,sizeof(ch[0]));
            pre[0]=-1;
            step[0]=0;
        }
        void add(int c)
        {
            c-='a';
            int p=last,np=++tot;
            step[np]=step[p]+1;
            memset(ch[np],-1,sizeof(ch[np]));
            while(~p&&ch[p][c]==-1) ch[p][c]=np,p=pre[p];
            if(p==-1) pre[np]=0;
            else{
                int q=ch[p][c];
                if(step[q]!=step[p]+1){
                    int nq=++tot;
                    step[nq]=step[p]+1;
                    memcpy(ch[nq],ch[q],sizeof(ch[q]));
                    pre[nq]=pre[q];
                    pre[q]=pre[np]=nq;
                    while(~p&&ch[p][c]==q) ch[p][c]=nq,p=pre[p];
                }
                else pre[np]=q;
            }
            last=np;
        }
    };SAM A,B;
    
    ll dfs2(int u)
    {
        if(u==-1) return 0;
        ll &res=dp2[u];
        if(~res) return res;
        res=1;
        REP(c,0,25) res+=dfs2(B.ch[u][c]);
        return res;
    }
    
    ll dfs1(int u)
    {
        ll &res=dp1[u];
        if(~res) return res;
        res=1;
        REP(c,0,25){
            if(~A.ch[u][c]) res+=dfs1(A.ch[u][c]);
            else res+=dfs2(B.ch[0][c]);
        }
        return res;
    }
    
    void solve()
    {
        A.init();B.init();
        int ls=strlen(s),lt=strlen(t);
        REP(i,0,ls-1) A.add(s[i]);
        REP(i,0,lt-1) B.add(t[i]);
        memset(dp1,-1,sizeof(dp1));
        memset(dp2,-1,sizeof(dp2));
        printf("%I64u
    ",dfs1(0));
    }
    
    int main()
    {
        freopen("in.txt","r",stdin);
        int T;cin>>T;
        while(T--){
            scanf("%s%s",s,t);
            solve();
        }
        return 0;
    }
    View Code
    没有AC不了的题,只有不努力的ACMER!
  • 相关阅读:
    序列化注意事项
    HTML5的新结构标签
    MVC模型
    CSS选择器权重计算规则
    HTML常用布局
    盒模型
    Spring Security 学习笔记-session并发控制
    java实例之随机点名
    java之方法重载
    java之方法
  • 原文地址:https://www.cnblogs.com/--560/p/5457826.html
Copyright © 2020-2023  润新知