字符串数据结构模板/题单(后缀数组,后缀自动机,LCP,后缀平衡树,回文自动机)...

模板

后缀数组

#include<bits/stdc++.h>
#define R register int
using namespace std;
const int N=1e6+9;
int sa[N],rk[N],hei[N],x[N],y[N],c[N];
char s[N];
void Rsort(R n,R m){
    for(R i=1;i<=n;++i)++c[x[i]];
    for(R i=2;i<=m;++i)c[i]+=c[i-1];
    for(R i=n;i;--i)sa[c[x[y[i]]]--]=y[i];
}
int main(){
    R n=fread(s+1,1,N,stdin)-1,m=122;
    for(R i=1;i<=n;++i)x[i]=s[i],y[i]=i;
    Rsort(n,m);
    for(R k=1,p=0;k<=n;k<<=1,p=0){
        for(R i=n-k+1;i<=n;++i)y[++p]=i;
        for(R i=1;i<=n;++i)if(sa[i]>k)y[++p]=sa[i]-k;
        memset(c+1,0,4*m);Rsort(n,m);memcpy(y+1,x+1,4*n);
        x[sa[1]]=p=1;
        for(R i=2;i<=n;++i)
            x[sa[i]]=p+=y[sa[i]]!=y[sa[i-1]]||y[sa[i]+k]!=y[sa[i-1]+k];
        if((m=p)==n)break;
    }
    for(R i=1;i<=n;++i)rk[sa[i]]=i;
    for(R i=1,p=0;i<=n;++i){
        for(p-=(bool)p;s[i+p]==s[sa[rk[i]-1]+p];++p);
        hei[rk[i]]=p;
    }
    for(R i=1;i<=n;++i)printf("%d ",sa[i]);puts("");
    for(R i=1;i<=n;++i)printf("%d ",rk[i]);puts("");
    for(R i=1;i<=n;++i)printf("%d ",hei[i]);puts("");
    return 0;
}

后缀自动机

hiho1445 后缀自动机二·重复旋律5

#include<bits/stdc++.h>
#define RG register
#define R RG int
using namespace std;
const int N=2e6+9;
int lst=1,nod=1,ch[N][26],fa[N],len[N];
char s[N];
void Extend(R c){
    R f=lst,p=lst=++nod;
    len[p]=len[f]+1;
    while(f&&!ch[f][c])ch[f][c]=p,f=fa[f];
    if(!f){fa[p]=1;return;}
    R x=ch[f][c];
    if(len[x]==len[f]+1){fa[p]=x;return;}
    R y=++nod;memcpy(ch[y],ch[x],104);
    len[y]=len[f]+1;fa[y]=fa[x];fa[x]=fa[p]=y;
    while(f&&ch[f][c]==x)ch[f][c]=y,f=fa[f];
}
int main(){
    for(char c=getchar();c>='a';c=getchar())Extend(c-'a');
    long long ans=0;
    for(R i=1;i<=nod;++i)ans+=len[i]-len[fa[i]];
    cout<<ans<<endl;
    return 0;
}

广义后缀自动机

注意两个特判
第一个特判是因为已经有这个状态了
第二个特判是因为分裂出y后,p失去意义了
大多数时候,模式串是独立的,可以每次把lst重赋值为1
如果模式串是Trie的话,DFS建SAM会被卡成\(O(叶节点个数×|S|)\)
正确写法是在BFS遍历Trie时进行Extend,详情参考XZY巨佬的总结
洛谷P3346 [ZJOI2015]诸神眷顾的幻想乡

#include<bits/stdc++.h>
#define LL long long
#define RG register
#define R RG int
#define G if(++ip==ie)if(fread(ip=buf,1,SZ,stdin))
using namespace std;
const int SZ=1<<19,N=2e5+9,M=10*N;
char buf[SZ],*ie=buf+SZ,*ip=ie-1;
inline int in(){
    G;while(*ip<'-')G;
    R x=*ip&15;G;
    while(*ip>'-'){x*=10;x+=*ip&15;G;}
    return x;
}
int he[N],ne[N],to[N];
char s[N];
namespace GSAM{
    int nod=1,ch[2*M][10],fa[2*M],len[2*M];
    int Extend(R f,R c){
        if(len[ch[f][c]]==len[f]+1)return ch[f][c];
        R p=++nod;
        len[p]=len[f]+1;
        while(f&&!ch[f][c])ch[f][c]=p,f=fa[f];
        if(!f)return fa[p]=1,p;
        R x=ch[f][c];
        if(len[x]==len[f]+1)return fa[p]=x,p;
        R y=++nod,lst=len[p]==len[f]+1?y:p;
        memcpy(ch[y],ch[x],sizeof(ch[y]));
        len[y]=len[f]+1;fa[y]=fa[x];fa[x]=fa[p]=y;
        while(f&&ch[f][c]==x)ch[f][c]=y,f=fa[f];
        return lst;
    }
    LL calc(){
        LL ans=0;
        for(R i=1;i<=nod;++i)ans+=len[i]-len[fa[i]];
        return ans;
    }
}
namespace Trie{
    int p,ch[M][10],lst[M],q[M];
    void dfs(R&u,R x,R f){
        if(!u)u=++p;
        for(R i=he[x];i;i=ne[i])
            if(to[i]!=f)dfs(ch[u][s[to[i]]],to[i],x);
    }
    void bfs(){
        lst[0]=1;
        for(R h=0,t=0;h<=t;++h)
            for(R x=q[h],y,i=0;i<10;++i)
                if((y=ch[x][i]))lst[q[++t]=y]=GSAM::Extend(lst[x],i);
    }
}
int main(){
    R n=in(),m=in();
    for(R i=1;i<=n;++i)s[i]=in();
    for(R i=1,p=0;i<n;++i){
        R x=in(),y=in();
        ne[++p]=he[x];to[he[x]=p]=y;
        ne[++p]=he[y];to[he[y]=p]=x;
    }
    for(R i=1;i<=n;++i)
        if(!ne[he[i]])Trie::dfs(Trie::ch[0][s[i]],i,0);
    Trie::bfs();
    printf("%lld\n",GSAM::calc());
    return 0;
}

后缀平衡树

不会

回文自动机

会板子了qaq
洛谷日报——强势图解回文自动机
洛谷P3649 [APIO2014]回文串

#include<bits/stdc++.h>
#define LL long long
#define R register int
using namespace std;
const int N=3e5+9;
char s[N];
int lst,nod=1,f[N],ch[N][26],len[N],sum[N];
inline void Extend(R i,R c){
    R p=lst;
    while(s[i-len[p]-1]!=s[i])p=f[p];
    if(!ch[p][c]){
        R q=f[p];
        while(s[i-len[q]-1]!=s[i])q=f[q];
        f[++nod]=ch[q][c];//注意先求fail再给ch赋值
        len[ch[p][c]=nod]=len[p]+2;
    }
    ++sum[lst=ch[p][c]];
}
int main(){
    len[f[0]=f[1]=1]=-1;
    cin>>(s+1);
    R n=strlen(s+1);LL ans=0;
    for(R i=1;i<=n;++i)Extend(i,s[i]-'a');
    for(R x=nod;x;--x){//PAM建出来自带拓扑序直接for
        ans=max(ans,(LL)sum[x]*len[x]);
        sum[f[x]]+=sum[x];
    }
    cout<<ans<<endl;
    return 0;
}

题单

hihocoder 重复旋律系列

【Done】重复旋律1(一个串的最长k重可重叠子串)
【Todo】重复旋律2(一个串的最长多重不可重叠子串)
【Done】重复旋律3(两个串的最长公共子串)
【Done】重复旋律4(一个串的周期重复次数最多的子串)
【Done】SAM基本概念
【Done】重复旋律5(一个串的本质不同子串个数)
【Done】重复旋律6(一个串的最长k重可重叠子串(对所有的k求答案))
【Todo】重复旋律7(一个数字串的本质不同子串的数值和)
【Todo】重复旋律8(一个文本串中与某模式串循环同构的子串计数)
【Todo】重复旋律9(字符串上的博弈)

自己发现or分享的一些好题

【Done】洛谷CF666E Forensic Examination
【Todo】洛谷CF700E Cool Slogans
【Todo】HDU5343 MZL's Circle Zhou(vjudge)
【Todo】HDU4622 Reincarnation(vjudge)(可做\(n,q\le10^5\)


【Todo】BZOJ3682 Phorni
【Todo】BZOJ2555 SubString

其他大佬的题单

https://www.cnblogs.com/Macaulish/p/4296557.html
https://www.cnblogs.com/mangoyang/p/9760416.html
https://blog.csdn.net/qq_39898877/article/details/82729385
https://www.cnblogs.com/xzyxzy/p/9186759.html

转载于:https://www.cnblogs.com/flashhu/p/10039708.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值