BZOJ 3998 [TJOI2015]弦论 ——后缀自动机
直接构建后缀自动机。
然后。
然后只需要再后缀自动机的go树上类似二分的方法进行查找即可,实际上是“26分”。
然后遇到了处理right集合的问题,然后觉得在go和parent树上上传都是可以的,毕竟一个是向后添加(go),而另一个是向前添加(parent),然后计算出来之后就类似平衡树的查找方式进行查找即可。
然后就A掉了
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #define maxn 1000005 struct SuffixAuto{ char s[maxn]; int last,cnt,t,k,len,v[maxn],q[maxn],rit[maxn]; int l[maxn],go[maxn][26],fa[maxn],sum[maxn]; void init() { memset(go,0,sizeof go); last=cnt=1; } void add(int x) { int p=last,np=last=++cnt; l[np]=l[p]+1; rit[np]=1; for (;p&&!go[p][x];p=fa[p]) go[p][x]=np; if (!p) fa[np]=1; else { int q=go[p][x]; if (l[q]==l[p]+1) fa[np]=q; else { int nq=++cnt; l[nq]=l[p]+1; memcpy(go[nq],go[q],sizeof go[q]); fa[nq]=fa[q]; fa[q]=fa[np]=nq; for (;p&&go[p][x]==q;p=fa[p]) go[p][x]=nq; } } } void build() { scanf("%s",s+1); len=strlen(s+1); F(i,1,len) add(s[i]-'a'); scanf("%d%d",&t,&k); F(i,1,cnt) v[l[i]]++; F(i,1,len) v[i]+=v[i-1]; D(i,cnt,1) q[v[l[i]]--]=i; D(i,cnt,1) { int tmp=q[i]; if (t) rit[fa[tmp]]+=rit[tmp]; else rit[tmp]=1; } rit[1]=0; D(i,cnt,1) { int tmp=q[i]; sum[tmp]=rit[tmp]; F(j,0,25) sum[tmp]+=sum[go[tmp][j]]; } } void dfs(int o,int x) { if (x<=rit[o]) return ; x-=rit[o]; F(i,0,25) if (go[o][i]){ if (x>sum[go[o][i]]) x-=sum[go[o][i]]; else { printf("%c",'a'+i); dfs(go[o][i],x); return; } } } void solve() { if (k>sum[1]) printf("-1\n"); else dfs(1,k); } }sam; int main() { sam.init(); sam.build(); sam.solve(); }