【后缀自动机】洛谷P3804模板题
题目描述
给定一个只包含小写字母的字符串S,
请你求出 S 的所有出现次数不为 1 的子串的出现次数乘上该子串长度的最大值。
输入输出格式
输入格式:一行一个仅包含小写字母的字符串S
输出格式:一个整数,为 所求答案
输入输出样例
输入样例#1:
abab
输出样例#1:
4
说明
对于10%的数据,|S|<=1000
对于100%的数据,|S|<=10^6
题解
只会后缀自动机的部分。。。
其他的是贴的欸嘿嘿
代码
//by 减维 #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<bitset> #include<set> #include<cmath> #include<vector> #include<map> #include<ctime> #include<algorithm> #define ll long long #define db double #define inf 1<<30 #define maxn 3000005 #define eps 1e-8 using namespace std; struct SAM{ int to[26],par,len; }e[maxn]; char a[maxn],st[maxn]; int last=1,rt=1,sz=1,tot,siz[maxn],du[maxn],ax[maxn]; ll ans=0; void add(int x) { int p=last,np=++sz; e[np].len=e[p].len+1; for(;p&&!e[p].to[x];p=e[p].par) e[p].to[x]=np; if(!p) e[np].par=rt; else{ int q=e[p].to[x]; if(e[q].len==e[p].len+1) e[np].par=q; else{ int nq=++sz; e[nq]=e[q];e[nq].len=e[p].len+1; e[np].par=e[q].par=nq; for(;p&&e[p].to[x]==q;p=e[p].par) e[p].to[x]=nq; } } last=np; siz[np]=1; } void calc() { for(int i=1;i<=sz;++i)du[e[i].len]++; for(int i=1;i<=sz;++i)du[i]+=du[i-1]; for(int i=1;i<=sz;++i)ax[du[e[i].len]--]=i; for(int i=sz;i;--i) { int p=ax[i]; siz[e[p].par]+=siz[p]; if(siz[p]>1)ans=max(ans,(ll)siz[p]*e[p].len); } } int main() { scanf("%s",a); for(int i=0;a[i];i++)add(a[i]-'a'); calc(); printf("%lld",ans); return 0; }
学会后缀自动机了!(大概。。。)
反正自己想到了一个建出来后缀树的做法2333
代码
//by 减维 #include<set> #include<map> #include<ctime> #include<cmath> #include<queue> #include<bitset> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define ll long long #define il inline #define db double #define rg register #define mpr make_pair #define maxn 3000005 #define eps 1e-8 #define inf (1<<30) #define pi 3.1415926535897932384626L using namespace std; inline int read() { int ret=0;bool fla=0;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-'){fla=1;ch=getchar();} while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();} return fla?-ret:ret; } struct edge{ int to,ne; }e[maxn<<1]; int n,ecnt,siz[maxn],dis[maxn],head[maxn]; ll ans; char s[maxn]; void add(int x,int y) { e[++ecnt]=(edge){y,head[x]};head[x]=ecnt; //e[++ecnt]=(edge){x,head[y]};head[y]=ecnt; } namespace SAM{ int to[maxn][26],par[maxn],len[maxn]; int sz=1,las=1; void ins(int x) { int p=las,np=++sz,q,nq; las=np;len[np]=len[p]+1; for(;p&&!to[p][x];p=par[p]) to[p][x]=np; if(!p) par[np]=1; else{ q=to[p][x]; if(len[q]==len[p]+1) par[np]=q; else{ nq=++sz;par[nq]=par[q];len[nq]=len[p]+1; memcpy(to[nq],to[q],sizeof to[q]); par[q]=par[np]=nq; for(;p&&to[p][x]==q;p=par[p]) to[p][x]=nq; } } siz[np]=1; } void build() { for(int i=2;i<=sz;++i) add(par[i],i);//,printf("%d %d\n",i,par[i]); } } void dfs(int x) { //siz[x]=1; for(int i=head[x];i;i=e[i].ne) { int dd=e[i].to; dis[dd]=dis[x]+SAM::len[dd]-SAM::len[x]; dfs(dd); siz[x]+=siz[dd]; } if(siz[x]!=1) ans=max(ans,1ll*siz[x]*dis[x]); } int main() { scanf("%s",s+1); n=strlen(s+1); for(int i=1;i<=n;++i) SAM::ins(s[i]-'a'); SAM::build(); dfs(1); printf("%lld",ans); return 0; }