[TJOI2015]弦论
重学了一下SAM
终终终终终于差不多知道他的实现原理了qaqaqaq
P3975 [TJOI2015]弦论
先建SAM
对于t=0的每个节点的size都是1,对于t=1的每个节点的size就是子树内叶子的个数
然后维护子树和以后就是一个类似求权值平衡树第k大的感觉
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int M =1000001;
int tag,K,las=1,cnt=1,n,m,k,d[M][26],f[M],len[M],a[M];
LL S[M],sz[M];
char c[M];
struct vv
{
int pos,len;
} t[M];
void SAM(int k)
{
int x=++cnt, y=las; len[x]=len[y]+1; sz[x]=1; las=x;
for(;y && !d[y][k];y=f[y]) d[y][k]=x;
if(!y){ f[x]=1; return ;}
int p=d[y][k];
if(len[p]==len[y]+1) {f[x]=p; return ;}
int np=++cnt;
len[np]=len[y]+1;
f[np]=f[p];
f[p]=f[x]=np;
memcpy(d[np],d[p],sizeof(d[p]));
for(;y && d[y][k]==p;y=f[y]) d[y][k]=np;
}
bool cmp(vv a,vv b)
{
return a.len>b.len;
}
int main()
{
//freopen("s1.txt","r",stdin);
scanf("%s",c+1);
scanf("%d%d",&tag,&K);
n=strlen(c+1);
for(int i=1;i<=n;i++) SAM(c[i]-'a');
for(int i=1;i<=cnt;i++)
{
t[i].pos=i;
t[i].len=len[i];
}
sort(t+1,t+1+cnt,cmp);
for(int i=1;i<=cnt;i++)
{
if(tag) sz[f[t[i].pos]]+=sz[t[i].pos];
else sz[t[i].pos]=1;
}
sz[1]=0;
for(int i=1;i<=cnt;i++)
{
S[t[i].pos]=sz[t[i].pos];
for(int j=0;j<26;j++) S[t[i].pos]+=S[d[t[i].pos][j]];
}
if(S[1]<K) { printf("-1"); return 0;}
int now=1;
while(1)
{
if(K<=sz[now]) break;
K-=sz[now];
for(int i=0;i<26;i++) if(d[now][i] && S[d[now][i]]>=K)
{
printf("%c",i+'a');
now=d[now][i];
break;
}
else K-=S[d[now][i]];
}
}