zoukankan      html  css  js  c++  java
  • 并不对劲的spoj nsubstr

    题意是求一个字符串每个长度的子串出现次数最多的那个出现了多少次,也就是求每个到根的最长路的right集合最大值 。

    先建后缀自动机,然后将每个前缀所在的集合的初值设为1,因为所有前缀的right集合肯定不相同,而且它们包含了所有位置。

    接下来按到根的最长距离从大到小排序,将right集合累加到parent上。这么排序是因为到根的最长距离长的状态肯定不是到根的最长距离短的状态的parent。

    最后直接求到根的不同的最长距离的最大的right集合就行。

    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #define maxn 250010
    using namespace std;
    int ans,len,p;
    int read()
    {
        int f=1,x=0;char ch=getchar();
        while(isdigit(ch)==0 && ch!='-')ch=getchar();
        if(ch=='-')f=-1,ch=getchar();
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    void write(int x)
    {
        int ff=0;char ch[15];
        while(x)ch[++ff]=(x%10)+'0',x/=10;
        if(ff==0)putchar('0'); 
        while(ff)putchar(ch[ff--]);
        putchar('
    ');
    }
    typedef struct node
    {
        int to[30],dis,fa;
    }spot;
    //求每个dis的right集合最大值 
    //不是每个状态的right集合!! 
    //ass♂we♂can♂
    struct SAM
    {
        spot x[maxn<<1];
        int ls,ls2,q,cnt,rt,lst,c[maxn<<1],ord[maxn<<1],ans[maxn<<1],maxl[maxn<<1];
        int right[maxn<<1],f[maxn<<1];
        char s[maxn];
        inline void start()
        {
            lst=rt=++cnt;
            scanf("%s",s+1);
            ls=strlen(s+1);
            for(int i=1;i<=ls;i++)
                extend(i);
        }
        inline void extend(int pos)
        {
            int val=s[pos]-'a',p=lst,np=++cnt;
            lst=np,x[np].dis=pos;
            for(;p&&x[p].to[val]==0;p=x[p].fa)x[p].to[val]=np;
            if(p==0)x[np].fa=rt;
            else
            {
                int q=x[p].to[val];
                if(x[q].dis==x[p].dis+1)x[np].fa=q;
                else
                {
                    int nq=++cnt;
                    x[nq].dis=x[p].dis+1;
                    memcpy(x[nq].to,x[q].to,sizeof(x[q].to));
                    x[nq].fa=x[q].fa,x[np].fa=x[q].fa=nq;
                    for(;x[p].to[val]==q;p=x[p].fa)x[p].to[val]=nq;
                }
            }
        }
        inline void qsort()
        {
            for(int i=1;i<=cnt;i++)
                c[x[i].dis]++; 
            for(int i=1;i<=ls;i++)
                c[i]+=c[i-1];
            for(int i=1;i<=cnt;i++)
                ord[c[x[i].dis]--]=i; 
        }
        inline void work()
        {
            for(int i=1,p=rt;i<=ls;i++)
                p=x[p].to[s[i]-'a'],right[p]=1;
            for(int i=cnt;i>=1;i--){int u=ord[i];right[x[u].fa]+=right[u];}
            for(int i=1;i<=cnt;i++)f[x[i].dis]=max(f[x[i].dis],right[i]);
            for(int i=ls;i>=1;i--)f[i]=max(f[i],f[i+1]);
            for(int i=1;i<=ls;i++)write(f[i]);
        //    cout<<"He doesn't have hands->"<<endl;
        }
    }t;
    int main()
    {
        t.start();
        t.qsort();
        t.work();
        return 0;
    }
    并不对劲的SAM

    听某位大佬说后缀自动机能解决所有不是字符串dp的字符串题。

  • 相关阅读:
    什么是 canvas(画布)?
    JavaScript
    JavaScript函数
    JavaScript事件
    JavaScript获取元素
    文件拷贝——高淇JAVA300讲笔记之IO和File
    读取与写出文件——高淇JAVA300讲笔记之IO和File
    File类的常用方法2——高淇JAVA300讲笔记之IO和File
    File类的常用方法1——高淇JAVA300讲笔记之IO和File
    路径常量,绝对路径与相对路径,构造File对象——高淇JAVA300讲笔记之IO和File
  • 原文地址:https://www.cnblogs.com/xzyf/p/8318236.html
Copyright © 2011-2022 走看看