后缀自动机的一些题目的整理
后缀自动机的一些题目的整理
P3804 【模板】后缀自动机(SAM)
板子题,没啥好说的。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e6+5;
int tot=1,last=1,idx,n;
int ver[N],h[N],ne[N];
char s[N];
ll f[N],ans;
struct node
{
int len,fa;
int ch[26];
}a[N];
void extend(int c)
{
int p=last,np=++tot;
last=np;
f[tot]=1;
a[np].len=a[p].len+1;
while(p&&!a[p].ch[c])
{
a[p].ch[c]=np;
p=a[p].fa;
}
if(!p) a[np].fa=1;
else
{
int q=a[p].ch[c];
if(a[q].len==a[p].len+1) a[np].fa=q;
else
{
int nq=++tot;
a[nq]=a[q];
a[nq].len=a[p].len+1;
a[q].fa=a[np].fa=nq;
while(p&&a[p].ch[c]==q)
{
a[p].ch[c]=nq;
p=a[p].fa;
}
}
}
}
void add(int x,int y)
{
ver[++idx]=y,ne[idx]=h[x],h[x]=idx;
}
void dfs(int u)
{
for(int i=h[u];i;i=ne[i])
{
dfs(ver[i]);
f[u]+=f[ver[i]];
}
if(f[u]>1) ans=max(ans,f[u]*a[u].len);
}
int main ()
{
cin>>s;
n=strlen(s);
for(int i=0;i<n;i++) extend(s[i]-'a');
for(int i=2;i<=tot;i++) add(a[i].fa,i);
dfs(1);
cout<<ans<<"\n";
return 0;
}
P5231 [JSOI2012] 玄武密码
类似于
#include <bits/stdc++.h>
using namespace std;
const int N=1e7+5;
int n,m;
int tot=1,last=1;
struct node
{
int len,fa;
int ch[4];
}a[N*2];
char s[N];
string ss;
void extend(int c)
{
int p=last,np=++tot;
last=np;
a[np].len=a[p].len+1;
while(p&&!a[p].ch[c])
{
a[p].ch[c]=np;
p=a[p].fa;
}
if(!p) a[np].fa=1;
else
{
int q=a[p].ch[c];
if(a[q].len==a[p].len+1) a[np].fa=q;
else
{
int nq=++tot;
a[nq]=a[q];
a[nq].len=a[p].len+1;
a[q].fa=a[np].fa=nq;
while(p&&a[p].ch[c]==q)
{
a[p].ch[c]=nq;
p=a[p].fa;
}
}
}
}
map<char,int> ma;
int main ()
{
ma['N']=0,ma['S']=1,ma['W']=2,ma['E']=3;
cin>>n>>m;
scanf("%s",s);
for(int i=0;s[i];i++) extend(ma[s[i]]);
while(m--)
{
scanf("%s",s);
int p=1,ret=0;
for(int i=0;s[i];i++)
{
int t=ma[s[i]];
if(a[p].ch[t]) p=a[p].ch[t],ret++;
else break;
}
cout<<ret<<"\n";
}
return 0;
}
P5341 [TJOI2019] 甲苯先生和大中锋的字符串
求出现
用差分数组统计出现的次数。
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,t,k,ans;
int tot=1,last=1;
int f[N],d[N];
struct node
{
int len,fa;
int ch[26];
}a[N];
char s[N];
void extend(int c)
{
int p=last,np=++tot;
last=np;
f[tot]=1;
a[np].len=a[p].len+1;
while(p&&!a[p].ch[c])
{
a[p].ch[c]=np;
p=a[p].fa;
}
if(!p) a[np].fa=1;
else
{
int q=a[p].ch[c];
if(a[q].len==a[p].len+1) a[np].fa=q;
else
{
int nq=++tot;
a[nq]=a[q];
a[nq].len=a[p].len+1;
a[q].fa=a[np].fa=nq;
while(p&&a[p].ch[c]==q)
{
a[p].ch[c]=nq;
p=a[p].fa;
}
}
}
}
int ver[N],ne[N],h[N],idx;
void add(int x,int y)
{
ver[++idx]=y,ne[idx]=h[x],h[x]=idx;
}
void dfs(int x)
{
for(int i=h[x];i!=-1;i=ne[i])
{
dfs(ver[i]);
f[x]+=f[ver[i]];
}
if(f[x]==k&&a[x].len) d[a[a[x].fa].len+1]++,d[a[x].len+1]--;
}
void clear()
{
tot=last=1;
idx=0;
ans=-1;
memset(d,0,sizeof d);
memset(a,0,sizeof a);
memset(f,0,sizeof f);
memset(h,-1,sizeof h);
}
void solve()
{
clear();
cin>>s;
n=strlen(s);
cin>>k;
for(int i=0;s[i];i++) extend(s[i]-'a');
for(int i=2;i<=tot;i++) add(a[i].fa,i);
dfs(1);
int mx=1;
for(int i=0;s[i];i++)
{
d[i+1]+=d[i];
if(d[i+1]>=mx)
{
mx=d[i+1];
ans=i+1;
}
}
if(ans==0) ans=-1;
cout<<ans<<"\n";
}
int main ()
{
cin>>t;
while(t--) solve();
return 0;
}
LONGCS - Longest Common Substring
LONGCS - Longest Common Substring
对第一个字符串建立
#include <bits/stdc++.h>
using namespace std;
const int N=2e4+5;
int n,m;
int tot=1,last=1;
struct node
{
int len,fa;
int ch[26];
}a[N];
int ans[N],now[N];
int ver[N],ne[N],h[N],idx;
char s[N];
void extend(int c)
{
int p=last,np=++tot;
last=np;
a[np].len=a[p].len+1;
while(p&&!a[p].ch[c])
{
a[p].ch[c]=np;
p=a[p].fa;
}
if(!p) a[np].fa=1;
else
{
int q=a[p].ch[c];
if(a[q].len==a[p].len+1) a[np].fa=q;
else
{
int nq=++tot;
a[nq]=a[q];
a[nq].len=a[p].len+1;
a[q].fa=a[np].fa=nq;
while(p&&a[p].ch[c]==q)
{
a[p].ch[c]=nq;
p=a[p].fa;
}
}
}
}
void add(int x,int y)
{
ver[++idx]=y,ne[idx]=h[x],h[x]=idx;
}
void dfs(int x)
{
for(int i=h[x];i!=-1;i=ne[i])
{
dfs(ver[i]);
now[x]=max(now[x],now[ver[i]]);
}
}
void solve()
{
tot=1,last=1,idx=0;
memset(a,0,sizeof a);
cin>>n;
cin>>s;
for(int i=0;s[i];i++) extend(s[i]-'a');
for(int i=1;i<=tot;i++) ans[i]=a[i].len;
memset(h,-1,sizeof h);
for(int i=2;i<=tot;i++) add(a[i].fa,i);
for(int i=1;i<n;i++)
{
cin>>s;
memset(now,0,sizeof now);
int p=1,t=0;
for(int j=0;s[j];j++)
{
int c=s[j]-'a';
while(p>1&&!a[p].ch[c]) p=a[p].fa,t=a[p].len;
if(a[p].ch[c]) p=a[p].ch[c],t++;
now[p]=max(now[p],t);
}
dfs(1);
for(int j=1;j<=tot;j++) ans[j]=min(ans[j],now[j]);
}
int res=0;
for(int i=1;i<=tot;i++) res=max(res,ans[i]);
cout<<res<<"\n";
}
int main ()
{
int t;
cin>>t;
while(t--) solve();
return 0;
}
NSUBSTR - Substrings
求长度为
不需要用数据结构来处理
因为一个字符串如果包含最长的字串有
#include <bits/stdc++.h>
using namespace std;
const int N=5e5+5;
int tot=1,last=1;
struct node
{
int len,fa;
int ch[26];
}a[N];
char s[N];
int f[N],ans[N];
void extend(int c)
{
int p=last,np=++tot;
last=np;
f[tot]=1;
a[np].len=a[p].len+1;
while(p&&!a[p].ch[c])
{
a[p].ch[c]=np;
p=a[p].fa;
}
if(!p) a[np].fa=1;
else
{
int q=a[p].ch[c];
if(a[q].len==a[p].len+1) a[np].fa=q;
else
{
int nq=++tot;
a[nq]=a[q];
a[nq].len=a[p].len+1;
a[q].fa=a[np].fa=nq;
while(p&&a[p].ch[c]==q)
{
a[p].ch[c]=nq;
p=a[p].fa;
}
}
}
}
int ver[N],ne[N],h[N],idx;
void add(int x,int y)
{
ver[++idx]=y,ne[idx]=h[x],h[x]=idx;
}
void dfs(int x)
{
for(int i=h[x];i!=-1;i=ne[i])
{
dfs(ver[i]);
f[x]+=f[ver[i]];
}
ans[a[x].len]=max(ans[a[x].len],f[x]);
}
int main ()
{
cin>>s;
int n=strlen(s);
for(int i=0;s[i];i++) extend(s[i]-'a');
memset(h,-1,sizeof h);
for(int i=2;i<=tot;i++) add(a[i].fa,i);
dfs(1);
for(int i=n;i>=1;i--) ans[i]=max(ans[i],ans[i+1]);
for(int i=1;i<=n;i++) cout<<ans[i]<<"\n";
return 0;
}
P3975 [TJOI2015] 弦论
建立
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
ll n,k,t;
char s[N];
int tot=1,last=1;
struct node
{
int len,fa;
int ch[26];
}a[N];
ll f[N],siz[N];
void extend(int c)
{
int p=last,np=++tot;
last=np;
siz[np]=1;
a[np].len=a[p].len+1;
while(p&&!a[p].ch[c])
{
a[p].ch[c]=np;
p=a[p].fa;
}
if(!p) a[np].fa=1;
else
{
int q=a[p].ch[c];
if(a[q].len==a[p].len+1) a[np].fa=q;
else
{
int nq=++tot;
a[nq]=a[q];
a[nq].len=a[p].len+1;
a[q].fa=a[np].fa=nq;
while(p&&a[p].ch[c]==q)
{
a[p].ch[c]=nq;
p=a[p].fa;
}
}
}
}
int ver[N],ne[N],h[N],idx;
void add(int x,int y)
{
ver[++idx]=y,ne[idx]=h[x],h[x]=idx;
}
void dfs1(int x)
{
for(int i=h[x];i;i=ne[i])
{
int y=ver[i];
dfs1(y);
siz[x]+=siz[y];
}
f[x]=siz[x];
}
int vis[N];
ll dfs2(int x)
{
if(vis[x]) return f[x];
vis[x]=1;
for(int i=0;i<26;i++)
{
int y=a[x].ch[i];
if(y) f[x]+=dfs2(y);
}
return f[x];
}
void query(int x,ll k)
{
if(k<=siz[x]) return ;
k-=siz[x];
for(int i=0;i<26;i++)
{
int y=a[x].ch[i];
if(k>f[y]) k-=f[y];
else
{
cout<<(char)('a'+i);
query(y,k);
return ;
}
}
}
int main ()
{
cin>>s;
n=strlen(s);
cin>>t>>k;
if(n*(n+1)/2<k)
{
cout<<-1<<"\n";
return 0;
}
for(int i=0;s[i];i++) extend(s[i]-'a');
for(int i=2;i<=tot;i++) add(a[i].fa,i);
if(t) dfs1(1);
else for(int i=1;i<=tot;i++) f[i]=siz[i]=1;
f[1]=siz[1]=0;
dfs2(1);
query(1,k);
return 0;
}
P3649 [APIO2014] 回文串
最恶心的一道题,
代码细节非常的多。
#include <bits/stdc++.h>
using namespace std;
const int N=6e5+5;
typedef long long ll;
int tot=1,last=1;
int n,m;
int p[N];
int st[N][20],lg[N],d[N],id[N],tp[N>>1];
int f[N];
ll ans;
char s[N>>1],t[N];
struct node
{
int fa,len;
int ch[26];
}a[N];
void extend(int c,int x)
{
int p=last,np=++tot;
last=np;
f[tot]=1;
tp[x]=tot;
a[np].len=a[p].len+1;
while(p&&!a[p].ch[c]) a[p].ch[c]=np,p=a[p].fa;
if(!p) a[np].fa=1;
else
{
int q=a[p].ch[c];
if(a[q].len==a[p].len+1) a[np].fa=q;
else
{
int nq=++tot;
a[nq]=a[q];
a[nq].len=a[p].len+1;
a[q].fa=a[np].fa=nq;
while(q&&a[p].ch[c]==q) a[p].ch[c]=nq,p=a[p].fa;
}
}
}
void check(int l,int r)
{
if(l<1||r>n||l>r) return ;
int pos=tp[r];
for(int i=lg[d[pos]];i;i--)
{
int x=st[pos][i];
if(a[x].len>=r-l+1) pos=x;
}
ans=max(ans,1ll*f[pos]*(r-l+1));
}
void manacher()
{
t[++m]='&';
for(int i=1;i<=n;i++) t[++m]='#',t[++m]=s[i],id[m]=i;
t[++m]='#';
t[++m]='*';
int mid=0,mr=0;
for(int i=1;i<=m;i++)
{
if(i<mr) p[i]=min(p[2*mid-i],mr-i);
else p[i]=1;
check(id[i-p[i]+2],id[i+p[i]-2]);
while(t[i+p[i]]==t[i-p[i]]) p[i]++,check(id[i-p[i]+2],id[i+p[i]-2]);
if(p[i]+i>mr)
{
mr=p[i]+i;
mid=i;
}
}
}
int c[N],b[N];
void build()
{
for(int i=1;i<=n;i++) extend(s[i]-'a',i);
for(int i=1;i<=tot;i++) c[a[i].len]++;
for(int i=1;i<=n;i++) c[i]+=c[i-1];
for(int i=1;i<=tot;i++) b[c[a[i].len]--]=i;
for(int i=tot;i;i--) f[a[b[i]].fa]+=f[b[i]];
for(int i=2;i<=tot;i++) lg[i]=lg[i>>1]+1;
for(int i=1;i<=tot;i++)
{
int pos=b[i],fa=a[pos].fa;
d[pos]=d[fa]+1;
st[pos][0]=fa;
for(int j=1;(1<<j)<=d[pos];j++) st[pos][j]=st[st[pos][j-1]][j-1];
}
}
int main ()
{
scanf("%s",s+1);
n=strlen(s+1);
build();
manacher();
cout<<ans<<"\n";
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」