zoukankan      html  css  js  c++  java
  • BZOJ3473 字符串 广义后缀自动机

    今天主攻了下SAM 好多东西以前都没理解到
    对于这道题 我们建一个自动机存所有串 每个穿last从1开始
    对于自动机上每个点额外记一个cnt 表示能匹配到这个点的不同串个数
    建完对每个串在自动机上匹配 把到的每个点$x$和$par[x],par[par[x]]…$的$cnt++$  
    然后就从父亲往儿子传递一下 这样每个点i就存了所有len[i]的数量 这里我用的拓扑序转移
    最后再对每个串在自动机上跑一遍 统计答案就好啦~

    #include<bits/stdc++.h>
    #define bug(x) cout<<(#x)<<" "<<(x)<<endl
    #define ll long long
    /*
    char *TT,*mo,but[(1<<15)+2];
    #define getchar() ((TT==mo&&(mo=(TT=but)+fread(but,1,1<<15,stdin),TT==mo))?-1:*TT++)//*/
    using namespace std;
    const int N=2e5+5;
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    ll ans[N];
    int n,k,amaz,tot,rt,last,cnt[N],ch[N][27],len[N],par[N],l[N],tmp[N],sum[N],dig[N],vis[N];
    string a[N];
    void extend(int x){
        int p=last,np=++tot;
        last=np,len[np]=len[p]+1;
        for(;p&&!ch[p][x];p=par[p]) ch[p][x]=np;
        if(!p) par[np]=rt;
        else{
            int q=ch[p][x];
            if(len[q]==len[p]+1) par[np]=q;
            else{
                int nq=++tot;
                memcpy(ch[nq],ch[q],sizeof ch[q]);
                len[nq]=len[p]+1;
                par[nq]=par[q];par[q]=par[np]=nq;
                for(;p&&ch[p][x]==q;p=par[p]) ch[p][x]=nq;
            }
        }
    }
    void top(){
        queue<int>q;
        for(int i=1;i<=tot;i++) if(!dig[i]) q.push(i),tmp[++amaz]=i;
        while(!q.empty()){
            int x=q.front();q.pop();
            if(!--dig[par[x]]) {
                q.push(par[x]),tmp[++amaz]=par[x];
            }
        }
        for(int i=amaz;i;i--) sum[tmp[i]]+=sum[par[tmp[i]]];
    }
    int main(){
    #ifdef Devil_Gary
        freopen("in.txt","r",stdin);
    #endif
        n=read(),k=read();
        rt=tot=last=1;
        for(int i=1;i<=n;i++){
            cin>>a[i];
            l[i]=a[i].length();
            last=1;
            for(int j=0;j<l[i];j++) extend(a[i][j]-'a');
        }
        for(int j=1;j<=n;j++){
            int p=1;
            for(int i=0;i<l[j];i++){
                p=ch[p][a[j][i]-'a'];
                int x=p;
                while(x&&vis[x]!=j) {
                    cnt[x]++,vis[x]=j,x=par[x];
                }
            }
        }
        for(int i=1;i<=tot;i++) dig[par[i]]++,sum[i]=(cnt[i]>=k)?(len[i]-len[par[i]]):0;
        top();
        for(int j=1;j<=n;j++){
            int p=1;
            for(int i=0;i<l[j];i++){
                p=ch[p][a[j][i]-'a'];
                ans[j]+=sum[p];
            }
            printf("%lld ",ans[j]);
        }
        return 0;
    }
    
  • 相关阅读:
    oo第四次总结
    oo第三次总结
    补给站总结
    OO第四次单元总结
    OO第三次单元总结
    OO第二次单元总结
    OO第一次单元总结
    提问回顾与个人总结
    软件工程结对作业博客
    OO第一次单元总结
  • 原文地址:https://www.cnblogs.com/devil-gary/p/8433339.html
Copyright © 2011-2022 走看看