BZOJ 1692: [Usaco2007 Dec]隊列變換 [尾碼數組 貪心]

來源:互聯網
上載者:User

標籤: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]隊列變換 [尾碼數組 貪心]

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.