Description 小 P 在看過電影《超時空接觸》(Contact)之後被深深的打動,決心致力於尋找外星人的事業。於是,他每天晚上都爬在屋頂上試圖用自己的收音機收聽外星人發來的信息。雖然他收聽到的僅僅是一些雜訊,但是他還是按照這些雜訊的高低電平將接收到的信號改寫為由 0 和 1 構成的串, 並 ...
Description
小 P 在看過電影《超時空接觸》(Contact)之後被深深的打動,決心致力於尋
找外星人的事業。於是,他每天晚上都爬在屋頂上試圖用自己的收音機收聽外星
人發來的信息。雖然他收聽到的僅僅是一些雜訊,但是他還是按照這些雜訊的高
低電平將接收到的信號改寫為由 0 和 1 構成的串, 並堅信外星人的信息就隱藏在
其中。他認為,外星人發來的信息一定會在他接受到的 01 串中重覆出現,所以
他希望找到他接受到的 01 串中所有重覆出現次數大於 1 的子串。但是他收到的
信號串實在是太長了,於是,他希望你能編一個程式來幫助他。
Input
輸入文件的第一行是一個整數N ,代表小 P 接收到的信號串的長度。
輸入文件第二行包含一個長度為N 的 01 串,代表小 P 接收到的信號串。
Output
輸出文件的每一行包含一個出現次數大於1 的子串所出現的次數。輸出的順
序按對應的子串的字典序排列。
Sample Input
71010101
Sample Output
33
2
2
4
3
3
2
2
HINT
對於 100%的數據,滿足 0 <= N <=3000
Source
做這道題之前我們需要首先明白一件事情 所有尾碼的首碼是字元串的子串 這樣我們就把子串的出現資次數轉換成了求尾碼的首碼的出現次數的問題 在尾碼的首碼上搞事情,這會讓你想到什麼? 沒錯!尾碼數組的Height數組 我們可以在Height數組裡面枚舉 字典序的話好處理,Height數組就是按字典序排的 首先枚舉排名,在Height數組中不斷枚舉首碼,對於每一個首碼,不斷往後枚舉Height,枚舉的時候統計次數。 哎呀說的好亂,自己看代碼把#include<cstdio> #include<iostream> #include<cstring> using namespace std; const int MAXN=2*1e6+10; int sa[MAXN],rak[MAXN],tp[MAXN],tax[MAXN],a[MAXN],N,M,height[MAXN]; char s[MAXN]; void Qsort() { for(int i=1;i<=M;i++) tax[i]=0; for(int i=1;i<=N;i++) tax[rak[i]]++; for(int i=1;i<=M;i++) tax[i]+=tax[i-1]; for(int i=N;i>=1;i--) sa[ tax[rak[tp[i]]]-- ] = tp[i]; } void Ssort() { M=127; for(int i=1;i<=N;i++) rak[i]=a[i],tp[i]=i;Qsort(); for(int w=1,p=1; p<N ; w<<=1,M=p) { p=0; for(int i=N-w+1;i<=N;i++) tp[++p]=i; for(int i=1;i<=N;i++) if(sa[i]>w) tp[++p]=sa[i]-w; Qsort(); swap(tp,rak); rak[sa[1]]=1;p=1; for(int i=2;i<=N;i++) rak[sa[i]] = (tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p; } int j,k=0; for(int i=1;i<=N;height[rak[i++]]=k) for(k=k?k-1:k,j=sa[rak[i]-1];a[i+k]==a[j+k];++k ); for(int i=0;i<=N;i++) { for(int j=height[i]+1;;j++) { int tot=1; for(int k=i+1;height[k]>=j;++k,++tot); if(tot>1) printf("%d\n",tot); else break; } } } int main() { #ifdef WIN32 freopen("a.in","r",stdin); #else #endif int Meiyong; cin>>Meiyong; scanf("%s",s); N=strlen(s); for(int i=1;i<=N;i++) a[i]=s[i-1]; Ssort(); return 0; }