description
求给定字符串的第(k(kle 10^9))大子串。无解输出-1,(nle 5 imes 10^5)
分不同位置的相同子串算作一个,不同位置的相同子串算作多个两种情况
solution
我们首先要建立一个(SAM)...
由于(SAM)相当于一个放了当前字符串的所有子串的(AC)自动机,
因此我们可以直接在(SAM)上进行查找
如果不同位置的相同子串算作一个,那么我们实际上要做的就是查找本质不同的第(k)大子串;
令(sum_i)表示当前查找到第(i)号节点后,从该节点出发能找到能被(SAM)识别的多少子串(包括空串)
求的时候只要把节点按照(len_i)拍个序,然后按照(SAM)的转移边像树形(DP)处理(sz)一样处理即可
for(RG int i=1;i<=tot;i++)t[len[i]]++;
for(RG int i=1;i<=tot;i++)t[i]+=t[i-1];
for(RG int i=1;i<=tot;i++)a[t[len[i]]--]=i;
//这里是基数排序
for(RG int i=1;i<=tot;i++)sum[i]=sz[i]=1;
sz[1]=sum[1]=0;
for(RG int i=tot;i;i--)
for(RG int j=0;j<26;j++)
sum[a[i]]+=sum[tr[a[i]][j]];
如果不同位置的相同子串算作多个,那么我们肯定要处理出(endpos_i(right_i))的大小((sz)):
void extend(int c){
...
sz[u]=1;
}
for(RG int i=1;i<=tot;i++)t[len[i]]++;
for(RG int i=1;i<=tot;i++)t[i]+=t[i-1];
for(RG int i=1;i<=tot;i++)a[t[len[i]]--]=i;
for(RG int i=tot;i;i--)sz[fa[a[i]]]+=sz[a[i]];
sz[1]=sum[1]=0;
for(RG int i=tot;i;i--)
for(RG int j=0;j<26;j++)
sum[a[i]]+=sum[tr[a[i]][j]];
然后向上面一样处理出(sum)即可
code
#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define FILE "a"
#define mp make_pair
#define pb push_back
#define RG register
#define il inline
using namespace std;
typedef unsigned long long ull;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
const dd eps=1e-10;
const int mod=1e9+7;
const int N=1000010;
const dd pi=acos(-1);
const int inf=2147483647;
const ll INF=1e18+1;
il ll read(){
RG ll data=0,w=1;RG char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
return data*w;
}
il void file(){
srand(time(NULL)+rand());
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
}
char s[N];
int n,b,k,tr[N][26],fa[N],sz[N],len[N],sum[N],a[N],t[N],tot=1,lst=1;
il void extend(int c){
RG int u=++tot,v=lst;lst=u;len[u]=len[v]+1;
while(v&&!tr[v][c])tr[v][c]=u,v=fa[v];
if(!v)fa[u]=1;
else{
RG int x=tr[v][c];
if(len[x]==len[v]+1)fa[u]=x;
else{
RG int y=++tot;len[y]=len[v]+1;
memcpy(tr[y],tr[x],sizeof(tr[y]));
fa[y]=fa[x];fa[x]=fa[u]=y;
while(v&&tr[v][c]==x)tr[v][c]=y,v=fa[v];
}
}
sz[u]=1;
}
il void search(int p,int x,int k){
if(sum[x]<k){puts("-1");exit(0);}
for(RG int i=0;i<26;i++)
if(tr[x][i]){
if(k<=sum[tr[x][i]]){
s[p]=i+'a';
if(k<=sz[tr[x][i]]){
s[p+1]=0;
printf("%s
",s+1);
exit(0);
}
else search(p+1,tr[x][i],k-sz[tr[x][i]]);
}
else k-=sum[tr[x][i]];
}
}
int main()
{
scanf("%s",s+1);n=strlen(s+1);b=read();k=read();
for(RG int i=1;i<=n;i++)extend(s[i]-'a');
//Case 1
for(RG int i=1;i<=tot;i++)t[len[i]]++;
for(RG int i=1;i<=tot;i++)t[i]+=t[i-1];
for(RG int i=1;i<=tot;i++)a[t[len[i]]--]=i;
for(RG int i=tot;i;i--)sz[fa[a[i]]]+=sz[a[i]];
for(RG int i=1;i<=tot;i++)sum[i]=sz[i]=(b?sz[i]:1);
sz[1]=sum[1]=0;
for(RG int i=tot;i;i--){
for(RG int j=0;j<26;j++)
sum[a[i]]+=sum[tr[a[i]][j]];
//printf("sum[%d]=%d,sz[%d]=%d
",a[i],sum[a[i]],a[i],sz[a[i]]);
}
//Case 2
search(1,1,k);
//Case 3
return 0;
}