后缀自动机 SAM
模板
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+50;
struct Node{
int ch[26];
int len,fa;
}node[maxn<<1];
int las=1,tot=1;
/*
结点node[]表示一个类
las是未加入此字符前的最长前缀(==整个串)所属的结点编号
tot是当前结点的总数
*/
int siz[maxn<<1];
ll num;//num 存不同子串的数量
ll alllen;//所有不同子串的总长度
void add(int c)
{
int p=las;int np=las=++tot;siz[tot]=1;
node[np].len=node[p].len+1;
for(;p&&!node[p].ch[c];p=node[p].fa)node[p].ch[c]=np;
//p=fa(p) 即从长到短遍历旧串的所有后缀
//node[p].ch[c]==0 如果旧串后缀添加新的字符c不是旧串字串 则 往新串的最长后缀所属结点连一条c边
if(!p)node[np].fa=1;//字符c在旧串没有出现过 所以新类的父类只能是1
else
{
int q=node[p].ch[c];
if(node[q].len==node[p].len+1)node[np].fa=q;//q是找到的第一个与np不同而又有后缀关系的结点
else//node[q].len>node[p].len+1
{
int nq=++tot;
node[nq]=node[q];//strcpy(node[nq].ch,node[q].ch);ndoe[nq].fa=node[q].fa;
node[nq].len=node[p].len+1;
node[q].fa=node[np].fa=nq;
for(;p&&node[p].ch[c]==q;p=node[p].fa)node[p].ch[c]=nq;
}
}
num+=node[np].len-node[node[np].fa].len;
alllen+=1ll*node[np].len*(node[np].len+1)/2-1ll*(node[node[np].fa].len)*(node[node[np].fa].len+1)/2;
}
char s[maxn];int len;
//求出现次数最多的子串的次数********************************************
//begin1
int mx;//mx是子串出现次数的最大次数
vector<int>p[maxn<<1];
void dfsinit(){
for(int i=2;i<=tot;i++)
p[node[i].fa].push_back(i);
}
void dfs(int u)
{
for(int i=0;i<p[u].size();i++)
{
dfs(p[u][i]);
siz[u]+=siz[p[u][i]];
}
if(siz[u]!=1)mx=max(mx,siz[u]);
}
void solve()
{
dfsinit();
dfs(1);
printf("%d\n",mx);
}
//end1
//输出第k小字符串*********************************************************
//begin2
/*
* 对于以下两种情况,在跑dfs2之前 让siz[1]=0 (siz[root]=0)
* 若是求可重复的第k小的字符串,则在dfs2()的函数里,让siz[u]=1,不用跑dfs
* 若是求本质不同第k小的字符串, 则先跑上边的dfsinit()和dfs() ,然后用下边的dfs2
*/
int siz2[maxn];bool vis[maxn];
void dfs2(int u)
{
siz2[u]=siz[u];vis[u]=true;
for(int i=0;i<26;i++)
if(node[u].ch[i])
{
if(!vis[node[u].ch[i]])dfs2(node[u].ch[i]);
siz2[u]+=siz2[node[u].ch[i]];
}
}
void getch(int u,int num)
{
num-=siz[u];
if(num<=0)return;
for(int i=0;i<26;i++)
{
if(num<=siz2[node[u].ch[i]])
{
putchar(i+'a');
getch(node[u].ch[i],num);
return;
}
num-=siz2[node[u].ch[i]];
}
}
//end2
//求本质不同第k小字符串 的bfs做法***********************************************
//begin3
int bb[maxn],id[maxn],sz[maxn];
void bfs(){
for(int i=1;i<=tot;i++)bb[node[i].len]++;
for(int i=1;i<=tot;i++)bb[i]+=bb[i-1];
for(int i=1;i<=tot;i++)id[bb[node[i].len]--]=i;
for(int i=tot;i>=1;i--){
sz[id[i]]=1;
for(int j=0;j<26;j++)
if(node[id[i]].ch[j])sz[id[i]]+=sz[node[id[i]].ch[j]];
}
}
void query(int k)
{
int u=1;
while(k)
{
for(int i=0;i<26;i++)
{
if(!node[u].ch[i])continue;
if(k>sz[node[u].ch[i]])k-=sz[node[u].ch[i]];
else{
putchar('a'+i);
u=node[u].ch[i];
k--;break;
}
}
}
puts("");
}
//end3
int main()
{
scanf("%s",s);len=strlen(s);
for(int i=0;i<len;i++)add(s[i]-'a');
int op,k;
scanf("%d%d",&op,&k);
//求第k小字符串
if(op){
dfsinit();
dfs(1);
}
else{
for(int i=2;i<=tot;i++)siz[i]=1;
}
siz[1]=0;
dfs2(1);
if(k>siz2[1]){
puts("-1");return 0;
}
getch(1,k);
}