1. 程式人生 > >p1940 [usaco2007dec_gold]佇列變換——字尾陣列模板題

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

很明顯,字尾陣列跑得快。但是佔空間大。。。。。。。。。。