1. 程式人生 > 實用技巧 >LG P3975 [TJOI2015]弦論

LG P3975 [TJOI2015]弦論

Description

對於一個給定的長度為n的字串,求出它的第k小子串是什麼。

Solution

對字串構建SAM,在parent樹上求出每個點的endpos集合大小,再在正向邊上求出所有子串個數,分本質不同和本質相同討論

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int t,k,length,las=1,tot=1,f[1000005],g[1000005],buc[1000005],topo[1000005];
char s[500005]; 
struct Node
{
    int ch[26
],fa,len; }sam[1000005]; inline int read() { int f=1,w=0; char ch=0; while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { w=(w<<1)+(w<<3)+ch-'0'; ch=getchar(); } return
f*w; } void insert(int c) { int p=las,np=las=++tot; sam[np].len=sam[p].len+1; f[np]=1; for(;p&&!sam[p].ch[c];p=sam[p].fa) { sam[p].ch[c]=np; } if(!p) { sam[np].fa=1; } else { int q=sam[p].ch[c]; if(sam[q].len==sam[p].len+1
) { sam[np].fa=q; } else { int nq=++tot; sam[nq]=sam[q]; sam[nq].len=sam[p].len+1; sam[q].fa=sam[np].fa=nq; for(;p&&sam[p].ch[c]==q;p=sam[p].fa) { sam[p].ch[c]=nq; } } } } void print(int x,int n) { if(n<=f[x]) { return; } n-=f[x]; for(int i=0;i<26;i++) { int v=sam[x].ch[i]; if(v) { if(n>g[v]) { n-=g[v]; } else { putchar(i+'a'); print(v,n); return; } } } } int main() { scanf("%s",s); length=strlen(s); t=read(); k=read(); for(int i=0;i<length;i++) { insert(s[i]-'a'); } for(int i=1;i<=tot;i++) { buc[sam[i].len]++; } for(int i=1;i<=tot;i++) { buc[i]+=buc[i-1]; } for(int i=1;i<=tot;i++) { topo[buc[sam[i].len]--]=i; } for(int i=tot;i>=1;i--) { f[sam[topo[i]].fa]+=f[topo[i]]; } if(!t) { for(int i=1;i<=tot;i++) { g[i]=f[i]=1; } } else { for(int i=1;i<=tot;i++) { g[i]=f[i]; } } f[1]=g[1]=0; for(int i=tot;i>=1;i--) { for(int j=0;j<26;j++) { if(sam[topo[i]].ch[j]) { g[topo[i]]+=g[sam[topo[i]].ch[j]]; } } } if(g[1]<k) { puts("-1"); } else { print(1,k); } return 0; }
[TJOI2015]弦論