p1940 [usaco2007dec_gold]佇列變換——字尾陣列模板題
題目
描述 Description
FJ打算帶他的N(1 <= N <= 30,000)頭奶牛去參加一年一度的“全美農場主
大獎賽”。在這場比賽中,每個參賽者都必須讓他的奶牛排成一列,然後領她們
從裁判席前依次走過。
今年,競賽委員會在接受隊伍報名時,採用了一種新的登記規則:他們把所
有隊伍中奶牛名字的首字母取出,按它們對應奶牛在隊伍中的次序排成一列(比
如說,如果FJ帶去的奶牛依次為Bessie、Sylvia、Dora,登記人員就把這支隊伍
登記為BSD)。登記結束後,組委會將所有隊伍的登記名稱按字典序升序排列,
就得到了他們的出場順序。
FJ最近有一大堆事情,因此他不打算在這個比賽上浪費過多的時間,也就是
說,他想盡可能早地出場。於是,他打算把奶牛們預先設計好的隊型重新調整一
下。
FJ的調整方法是這樣的:每次,他在原來佇列的首端或是尾端牽出一頭奶牛
,把她安排到新佇列的尾部,然後對剩餘的奶牛佇列重複以上的操作,直到所有
奶牛都被插到了新的佇列裡。這樣得到的佇列,就是FJ拉去登記的最終的奶牛隊
列。
接下來的事情就交給你了:對於給定的奶牛們的初始位置,計算出按照FJ的
調整規則所可能得到的字典序最小的佇列。
輸入格式 Input Format
第1行: 一個整數:N
- 第2…N+1行: 第i+1行僅有1個’A’…'Z’中的字母,表示佇列中從前往後數第i
頭奶牛名字的首字母
輸出格式 Output Format
第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 | CD | ABC |
#5 | CD | ABCB |
#6 | D | ABCBC |
#7 | ABCBCD |
時間限制 Time Limitation
1s
註釋 Hint
1s
來源 Source
usaco 2007 dec gold bclgold
題解
我第一次看到這道題,想到了貪心,(雖然題目上是字尾陣列),但是昨天聽過L老師講課,我就想著先打個暴力,然後再去學習字尾陣列,寫個一題多解:
這個做法就是貪心,從兩頭分別走,小的就進入佇列,若是兩頭相等,則整體考慮,取最優的一側,進入佇列。
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e4+10;
inline int read()
{
int f=1,num=0;
char ch=getchar();
while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar();}
while (isdigit(ch)) num=(num<<1)+(num<<3)+(ch^48), ch=getchar();
return num*f;
}
char ch[maxn];//原始資料
char q[maxn];//手寫佇列
int main()
{
int n=read();
for (int i=1;i<=n;++i)
cin>>ch[i];
int l=1,r=n,tail=0;//二分
while (l<=r)
{
if (ch[l]<ch[r])
q[++tail]=ch[l++];
else if (ch[l]==ch[r])
{
int i=l,j=r;
while (i!=j && ch[i]==ch[j]) ++i,--j;
if (ch[i]>ch[j]) q[++tail]=ch[r--];
else q[++tail]=ch[l++];
}
else
q[++tail]=ch[r--];
}
int m=0;
while (m!=n)
{
for (int i=1;i<=80;++i)
if (m!=n)
printf("%c",q[++m]);
printf("\n");
}
return 0;
}
結果
#01: Accepted (0ms, 568KB)
#02: Accepted (0ms, 568KB)
#03: Accepted (7ms, 568KB)
#04: Accepted (15ms, 568KB)
#05: Accepted (15ms, 568KB)
#06: Accepted (15ms, 568KB)
#07: Accepted (15ms, 568KB)
#08: Accepted (11ms, 568KB)
#09: Accepted (78ms, 568KB)
#10: Accepted (734ms, 568KB)
#11: Accepted (93ms, 568KB)
#12: Accepted (406ms, 568KB)
#13: Accepted (93ms, 568KB)
#14: Accepted (578ms, 568KB)
#15: Accepted (187ms, 568KB)
#16: Accepted (78ms, 568KB)
#17: Accepted (171ms, 568KB)
#18: Accepted (375ms, 568KB)
#19: Accepted (156ms, 568KB)
#20: Accepted (625ms, 568KB)
Accepted / 100 / 3660ms / 11360KB
好啦,去學字尾陣列了,學完再繼續碼部落格。
#include<bits/stdc++.h>
#define up(i,j,n) for(int i=j;i<=n;i++)
#define down(i,j,n) for(int i=j;i>=n;i--)
using namespace std;
typedef long long ll;
const int maxn=6e4+100;
const int inf=1e9;
inline int read()
{
int f=1,num=0;
char ch=getchar();
while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); }
while (isdigit(ch)) num=(num<<1)+(num<<3)+(ch^48), ch=getchar();
return num*f;
}
int a[maxn],x[maxn],y[maxn];
int c[maxn],sa[maxn],que[maxn];
inline void build_sa(int n,int m)
{
memset(c,0,sizeof(c));
up(i,0,n-1) c[x[i]=a[i]]++;
up(i,1,m-1) c[i]+=c[i-1];
down(i,n-1,0) sa[--c[x[i]]]=i;//初始化
for(int k=1;k<=n;k<<=1)
{
int p=0;
up(i,n-k,n-1) y[p++]=i;
up(i,0,n-1)
if (sa[i]>=k) y[p++]=sa[i]-k;//根據第二關鍵字排序
memset(c,0,sizeof(c));
up(i,0,n-1) c[x[y[i]]]++;
up(i,1,m-1) c[i]+=c[i-1];
down(i,n-1,0) sa[--c[x[y[i]]]]=y[i];//根據第一關鍵字排序
swap(x,y);
p=1,x[sa[0]]=0;
up(i,1,n-1) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
if (p>=n) break;
m=p;
}
}
int main()
{
int n=read();
int tot=2*n+1;
up(i,0,n-1)
{
char ch=getchar();
while (ch<'A'||ch>'Z') ch=getchar();
a[i]=ch-'A'+1;
}
a[n]=a[tot]=0;
up(i,1,n) a[n+i]=a[n-i];
build_sa(tot,27);
up(i,0,tot-1) que[sa[i]]=i;
int l=0,r=n-1,cnt=0;
while (l<=r)
{
if (que[l]<que[2*n-r]) printf("%c",a[l++]+'A'-1);
else printf("%c",a[r--]+'A'-1);
cnt++;
if (cnt%80==0) printf("\n");
}
if (cnt%80==0) printf("\n");
return 0;
}
結果
#01: Accepted (7ms, 3008KB)
#02: Accepted (15ms, 3008KB)
#03: Accepted (11ms, 3008KB)
#04: Accepted (15ms, 3008KB)
#05: Accepted (11ms, 3008KB)
#06: Accepted (31ms, 3008KB)
#07: Accepted (15ms, 3008KB)
#08: Accepted (11ms, 3008KB)
#09: Accepted (93ms, 3008KB)
#10: Accepted (93ms, 3008KB)
#11: Accepted (93ms, 3008KB)
#12: Accepted (93ms, 3008KB)
#13: Accepted (93ms, 3008KB)
#14: Accepted (93ms, 3008KB)
#15: Accepted (78ms, 3008KB)
#16: Accepted (93ms, 3008KB)
#17: Accepted (93ms, 3008KB)
#18: Accepted (78ms, 3008KB)
#19: Accepted (93ms, 3008KB)
#20: Accepted (93ms, 3008KB)
Accepted / 100 / 1214ms / 60160KB
很明顯,字尾陣列跑得快。但是佔空間大。。。。。。。。。。