標籤:ref desc for output problems gets include 整數 problem
1692: [Usaco2007 Dec]隊列變換Time Limit: 5 Sec Memory Limit: 64 MB
Submit: 1383 Solved: 582
[Submit][Status][Discuss]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 Input6
A
C
D
B
C
B
輸入說明:
FJ有6頭順次排好隊的奶牛:ACDBCB
Sample OutputABCBCD
輸出說明:
運算元 原隊列 新隊列
#1 ACDBCB
#2 CDBCB A
#3 CDBC AB
#4 CDB ABC
#5 CD ABCB
#6 D ABCBC
#7 ABCBCD
HINT Source
Gold
怎麼說呢,尾碼數組輔助貪心
貪心很明顯了,字典序 盡量選小的
問題是兩端的字元一樣怎麼選?
看看拿去兩端的一個後從左往右和從右往左誰的字典序更小就可以了....一樣的話無所謂,否則從小的一邊選一定會更優
如何快速比較首碼和尾碼的字典序?
把整個字串翻轉加一個特殊字元然後接在最後,尾碼數組求rnk
提示:
兩端可以head=1 tail=n1+2,也就是說右端使用翻轉後的左端,方便一點
//// main.cpp// bzoj1692//// Created by Candy on 2016/12/29.// Copyright © 2016年 Candy. All rights reserved.//#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int N=6e4+5;int n,n1,n2,m;char s[3],a[N];int sa[N],c[N],t1[N],t2[N];inline bool cmp(int *r,int a,int b,int j){ return a+j<=n&&b+j<=n&&r[a]==r[b]&&r[a+j]==r[b+j];}int rnk[N],height[N];void getHeight(char s[]){ int k=0; for(int i=1;i<=n;i++) rnk[sa[i]]=i; for(int i=1;i<=n;i++){ if(k) k--; if(rnk[i]==1) continue; int j=sa[rnk[i]-1]; while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k]) k++; height[rnk[i]]=k; }}void getSA(char s[]){ int *r=t1,*k=t2; for(int i=0;i<=m;i++) c[i]=0; for(int i=1;i<=n;i++) c[r[i]=s[i]]++; for(int i=1;i<=m;i++) c[i]+=c[i-1]; for(int i=n;i>=1;i--) sa[c[r[i]]--]=i; for(int j=1;j<=n;j<<=1){ int p=0; for(int i=n-j+1;i<=n;i++) k[++p]=i; for(int i=1;i<=n;i++) if(sa[i]>j) k[++p]=sa[i]-j; for(int i=0;i<=m;i++) c[i]=0; for(int i=1;i<=n;i++) c[r[k[i]]]++; for(int i=1;i<=m;i++) c[i]+=c[i-1]; for(int i=n;i>=1;i--) sa[c[r[k[i]]]--]=k[i]; swap(r,k);p=0;r[sa[1]]=++p; for(int i=2;i<=n;i++) r[sa[i]]=cmp(k,sa[i],sa[i-1],j)?p:++p; if(p>=n) break;m=p; }}int cnt=0,head,tail;void solve(){ head=1;tail=n1+2; for(int d=1;d<=n1;d++){ if(rnk[head]<rnk[tail]) putchar(a[head++]); else putchar(a[tail++]); if(d%80==0) putchar(‘\n‘); }}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%s",s),a[i]=s[0]; a[n+1]=1; for(int i=1;i<=n;i++) a[n+1+i]=a[n+1-i]; n1=n; n=n+n+1; m=300; getSA(a); getHeight(a); solve();}
BZOJ 1692: [Usaco2007 Dec]隊列變換 [尾碼數組 貪心]