1. 程式人生 > >TJOI2015 弦論

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("\n"); return 0; }