Description
FJ打算帶他的N(1 <= N <= 30,000)頭奶牛去參加一年一度的“全美農場主大獎賽”。在這場比賽中,每個參賽者都必須讓他的奶牛排成一列,然後領她們從裁判席前依次走過。 今年,競賽委員會在接受隊伍報名時,採用了一種新的登記規則:他們把所有隊伍中奶牛名字的首字母取出,按它們對應奶牛在隊伍中的次序排成一列(比如說,如果FJ帶去的奶牛依次為Bessie、Sylvia、Dora,登記人員就把這支隊伍登記為BSD)。登記結束後,組委會將所有隊伍的登記名稱按字典序升序排列,就得到了他們的出場順序。 FJ最近有一大堆事情,因此他不打算在這個比賽上浪費過多的時間,也就是說,他想儘可能早地出場。於是,他打算把奶牛們預先設計好的隊型重新調整一下。 FJ的調整方法是這樣的:每次,他在原來隊列的首端或是尾端牽出一頭奶牛,把她安排到新隊列的尾部,然後對剩餘的奶牛隊列重複以上的操作,直到所有奶牛都被插到了新的隊列裡。這樣得到的隊列,就是FJ拉去登記的最終的奶牛隊列。 接下來的事情就交給你了:對於給定的奶牛們的初始位置,計算出按照FJ的調整規則所可能得到的字典序最小的隊列。 Input
* 第1行: 一個整數:N
* 第2..N+1行: 第i+1行僅有1個'A'..'Z'中的字母,表示隊列中從前往後數第i 頭奶牛名字的首字母 Output
* 第1..??行: 輸出FJ所能得到的字典序最小的隊列。每行(除了最後一行)輸 出恰好80個'A'..'Z'中的字母,表示新隊列中每頭奶牛姓名的首 字母 Sample Input 6
A
C
D
B
C
B
輸入說明:
FJ有6頭順次排好隊的奶牛:ACDBCB
Sample Output ABCBCD
輸出說明:
運算元 原隊列 新隊列
#1 ACDBCB
#2 CDBCB A
#3 CDBC AB
#4 CDB ABC
#5 CD ABCB
#6 D ABCBC
#7 ABCBCD
題解: 首先如果左右單詞不一樣肯定是選字典序小的加入. 如果一樣的話可以比較以左邊字元開頭的尾碼和以右邊字元開頭的首碼。 所以把模板串反過來接到後面,中間加入一個分隔字元.建立尾碼數組. 然後首碼就可以轉化成尾碼直接比較了. 代碼:
#include<iostream>#include<cstdio>#include<cstring>#define N 60010using namespace std;int s[N],c[N],t1[N],t2[N],sa[N],rank[N],n,m,temp;char ch;bool cmp(int *y,int p,int q,int k){ int a=(p+k>=n)?-1:y[p+k]; int b=(q+k>=n)?-1:y[q+k]; return a==b&&y[p]==y[q];}void build_sa(int m){ int *x=t1,*y=t2; for (int i=0;i<m;i++) c[i]=0; for (int i=0;i<n;i++) c[x[i]=s[i]]++; for (int i=1;i<m;i++) c[i]+=c[i-1]; for (int i=n-1;i>=0;i--) sa[--c[x[i]]]=i; for (int k=1;k<=n;k<<=1){ int p=0; for (int i=n-k;i<n;i++) y[p++]=i; for (int i=0;i<n;i++) if (sa[i]>=k) y[p++]=sa[i]-k; for (int i=0;i<m;i++) c[i]=0; for (int i=0;i<n;i++) c[x[y[i]]]++; for (int i=1;i<m;i++) c[i]+=c[i-1]; for (int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1;x[sa[0]]=0; for (int i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],k)?p-1:p++; if (p>=n) break; m=p; } }int main(){ scanf("%d",&n);s[n]='$'; for(int i=0;i<n;i++){ scanf("%*c%c",&ch); s[2*n-i]=s[i]=ch; } m=n;n=n+n+1;build_sa(2666); for (int i=0;i<n;i++) rank[sa[i]]=i; //for (int i=0;i<n;i++) cout<<sa[i]<<' '; int l=0,r=m-1; while (l<r){ int a=rank[l],b=rank[m+m-r]; //cout<<l<<' '<<r<<' '<<a<<' '<<b<<' '; if (a<b){ printf("%c",s[l]);l++; } else{ printf("%c",s[r]);r--; } temp++; if (temp>=80&&(l!=r)){puts("");temp=0;} } printf("%c",s[l]);}