TJOI2015 弦论
Posted liguanlin1124
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TJOI2015 弦论相关的知识,希望对你有一定的参考价值。
题解:
鉴于子串我们很容易想到后缀自动机。
先建后缀自动机,然后处理单点价值以及对于每个点的总价值。
T=0要求去重,此时单点价值为1;
T=0要求不去重,此时单点价值为parent树上endpos的数量。后缀的前缀就是子串。
由于建成的后缀自动机有向无环,我们可以O(n)时间处理每个点的总价值,即sum[u]+=sum[to]。
时间复杂度O(n)。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 500050 #define ll long long char s[N]; int T,K; struct Point { int pre,len,trs[28]; }p[2*N]; struct SAM { int siz[2*N],v[2*N]; ll sum[2*N]; int tot,las; SAM(){tot=las=1;} int hed[2*N],cnt; struct EG { int to,nxt; }e[2*N]; void ae(int f,int t) { e[++cnt].to = t; e[cnt].nxt = hed[f]; hed[f] = cnt; } void insert(int c) { int np,nq,lp,lq; np=++tot; siz[np]=1; p[np].len = p[las].len+1; for(lp=las;lp&&!p[lp].trs[c];lp=p[lp].pre) p[lp].trs[c]=np; if(!lp)p[np].pre = 1; else { lq = p[lp].trs[c]; if(p[lq].len==p[lp].len+1)p[np].pre = lq; else { nq = ++tot; p[nq] = p[lq]; p[nq].len = p[lp].len+1; p[lq].pre = p[np].pre = nq; while(p[lp].trs[c]==lq) { p[lp].trs[c]=nq; lp=p[lp].pre; } } } las = np; } void dfs1(int u) { v[u]=T?siz[u]:1; for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; dfs1(to); if(T)v[u]+=v[to]; } } void dfs2(int u) { sum[u] = v[u]; for(int i=1;i<=26;i++) { int to = p[u].trs[i]; if(!to)continue; if(!sum[to])dfs2(to); sum[u]+=sum[to]; } } void build() { for(int i=2;i<=tot;i++) ae(p[i].pre,i); dfs1(1); v[1]=0; dfs2(1); } void cal(int k) { int u = 1; if(sum[1]<k) { printf("-1"); return ; } while(1) { for(int i=1;i<=26;i++) { if(k>sum[p[u].trs[i]])k-=sum[p[u].trs[i]]; else { printf("%c",‘a‘+i-1); u = p[u].trs[i]; k-= v[u]; break; } } if(k<=0)return ; } } }sam; int main() { scanf("%s%d%d",s+1,&T,&K); int len = strlen(s+1); for(int i=1;i<=len;i++) sam.insert(s[i]-‘a‘+1); sam.build(); sam.cal(K); printf(" "); return 0; }
以上是关于TJOI2015 弦论的主要内容,如果未能解决你的问题,请参考以下文章