【模板】后缀自动机SAM

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/85012166

参考题目:洛谷P3804


解析:

其实这个东西的理解的话,说难没有那么难,说简单也不是很简单。
这里先贴一个代码,什么时候再更新吧。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

typedef struct SAM_node *point;
struct SAM_node{
    int len,cnt;
    point fa,son[26];
    SAM_node():len(0),fa(NULL){memset(son,0,sizeof son);}
    inline point clear(int l=0){
        fa=NULL;
        len=l;
        memset(son,0,sizeof son);
        return this;
    }
};

cs int N=1000006;
struct SAM{
    SAM_node nd[N<<1];
    point now,last,pos[N<<1];
    int bin[N<<1];
    SAM():now(nd),last(nd){}
    inline void clear(){
        for(;now>nd;--now)now->clear();
        last=now=nd->clear();
    }
    
    inline void push_back(char c){
        c-='a';
        point cur=++now;
        cur->len=last->len+1;
        cur->cnt=1;
        point p=last;
        for(;p&&!p->son[c];p=p->fa)p->son[c]=cur;
        if(!p)cur->fa=nd;
        else if(p->son[c]->len==p->len+1)cur->fa=p->son[c];
        else {
            point clone=++now,q=p->son[c];
            *clone=*q;
            clone->len=p->len+1;
            clone->cnt=0;
            q->fa=cur->fa=clone;
            for(;p&&p->son[c]==q;p=p->fa)p->son[c]=clone;
        }
        last=cur;
    }
    
    inline ll calc(){
        re ll ans=0;
        for(point re i=nd;i<=now;++i)++bin[i->len];
        for(int re i=1;i<=now-nd;++i)bin[i]+=bin[i-1];
        for(point re i=nd;i<=now;++i)pos[bin[i->len]--]=i;
        for(int re i=now-nd;i;--i){
            if(pos[i]->fa)pos[i]->fa->cnt+=pos[i]->cnt;
            if(pos[i]->cnt^1)ans=max(ans,(ll)pos[i]->cnt*pos[i]->len);
        }
        return ans;
    }
}sam;

char s[N];int len;
signed main(){
    scanf("%s",s+1);len=strlen(s+1);
    for(int re i=1;i<=len;++i)sam.push_back(s[i]);
    printf("%lld",sam.calc());
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/85012166