并不对劲的[spoj nsubstr]substrings

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并不对劲的[spoj nsubstr]substrings相关的知识,希望对你有一定的参考价值。

题意是求一个字符串每个长度的子串出现次数最多的那个出现了多少次,也就是求每个到根的最长路的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(\n);
}
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的字符串题。

以上是关于并不对劲的[spoj nsubstr]substrings的主要内容,如果未能解决你的问题,请参考以下文章

●SPOJ 8222 NSUBSTR–Substrings

SPOJ8222/NSUBSTR:Substrings——题解

●SPOJ 8222 NSUBSTR - Substrings

[SPOJ-NSUBSTR]Substrings

[SPOJ8222]NSUBSTR - Substrings 后缀自动机

[SPOJ-NSUBSTR]Substrings