zoukankan      html  css  js  c++  java
  • bzoj3277 串

    题目描述

    题解:

    对于多串的子串,我们可以建出广义后缀自动机。

    由于本题询问的是(子串出现次数>=k)×len的总和,就将所有串扔到自动机中,爆跳pre并标记。每个点得到

    一个经过次数cnt。

    若cnt>=k,说明这个点压缩的所有子串都可以作为答案串。

    然后处理出每个点到根的树链上所有点的答案。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 100050
    #define ll long long
    int n,k;
    char s[N],sum[N];
    struct node
    {
        int pre,len,trs[28];
        int cnt;
    }p[2*N];
    int use[2*N],vis[2*N],ens[N],v[2*N];
    struct SAM
    {
        int tot,las;
        SAM(){tot=las=1;}
        void res(){las=1;}
        void insert(int c)
        {
            int np,nq,lp,lq;
            np = ++tot;
            p[np].len = p[las].len+1;
            for(lp=las;lp&&!p[lp].trs[c];lp=p[lp].pre)
                p[lp].trs[c]=np;
            if(!lp)p[np].pre = 1;
            else
            {
                lq = p[lp].trs[c];
                if(p[lq].len==p[lp].len+1)p[np].pre = lq;
                else
                {
                    nq = ++tot;
                    p[nq] = p[lq];
                    p[nq].len = p[lp].len+1;
                    p[lq].pre = p[np].pre = nq;
                    while(p[lp].trs[c]==lq)
                    {
                        p[lp].trs[c] = nq;
                        lp = p[lp].pre;
                    }
                }
            }
            las = np;
        }
        void dfs(int u)
        {
            if(u==1||vis[u])return ;vis[u]=1;
            v[u] = (p[u].cnt>=k)*(p[u].len-p[p[u].pre].len);
            dfs(p[u].pre);
            v[u]+=v[p[u].pre];
        }
        void build()
        {
            for(int i=1;i<=n;i++)
            {
                int u = 1;
                for(int j=ens[i-1]+1;j<=ens[i];j++)
                {
                    u = p[u].trs[sum[j]-'a'+1];
                    int tmp = u;
                    while(tmp!=1&&use[tmp]<i)
                    {
                        p[tmp].cnt++;
                        use[tmp] = i;
                        tmp = p[tmp].pre;
                    }
                }
            }
            for(int i=2;i<=tot;i++)dfs(i);
        }
    }sam;
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s+1);
            sam.res();
            int len = strlen(s+1);
            for(int j=1;j<=len;j++)
            {
                sam.insert(s[j]-'a'+1);
                sum[ens[i-1]+j]=s[j];
            }
            ens[i]=ens[i-1]+len;
        }
        sam.build();
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++)
        {
            int u = 1;
            ll c = 0;
            for(int j=ens[i-1]+1;j<=ens[i];j++)
            {
                u = p[u].trs[sum[j]-'a'+1];
                c+=v[u];
            }
            printf("%lld ",c);
        }
        printf("
    ");
        return 0;
    }
  • 相关阅读:
    DM9000网卡驱动接受数据从中断方式改成NAPI方式小记
    20130317
    c++版本新浪微博sdk库交叉编译
    新年预期小记
    arm+linux嵌入式系统的终端显示中文乱码解决
    记transmission下载sd卡支持不佳问题
    嵌入式linux自动登录
    SevenArmsSeries.Repositories
    Mybatis开启二级缓存(全局缓存)的方法
    Spring学习之动态代理的简单实现
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10122584.html
Copyright © 2011-2022 走看看