【BZOJ2882】工艺 [SAM]
工艺
Time Limit: 10 Sec Memory Limit: 128 MB[Submit][Status][Discuss]
Description
小敏和小燕是一对好朋友。
他们正在玩一种神奇的游戏,叫Minecraft。
他们现在要做一个由方块构成的长条工艺品。但是方块现在是乱的,而且由于机器的要求,他们只能做到把这个工艺品最左边的方块放到最右边。
他们想,在仅这一个操作下,最漂亮的工艺品能多漂亮。
两个工艺品美观的比较方法是,从头开始比较,如果第i个位置上方块不一样那么谁的瑕疵度小,那么谁就更漂亮,如果一样那么继续比较第i+1个方块。如果全都一样,那么这两个工艺品就一样漂亮。
Input
第一行两个整数n,代表方块的数目。
第二行n个整数,每个整数按从左到右的顺序输出方块瑕疵度的值。
Output
一行n个整数,代表最美观工艺品从左到右瑕疵度的值。
Sample Input
10
10 9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
Sample Output
1 10 9 8 7 6 5 4 3 2
HINT
对于100%的数据,n<=300000
Main idea
给定一个环,问从哪一位往后走开始得到的串字典序最小。
Solution
我们先把串复制一遍,然后建立一个SAM,然后贪心地走最小的即可。由于SAM的种种奇特♂性质,一定可以走完n个,输出即可。由于数字很大,数组不够存,于是我们使用map。
Code
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cstdio> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cmath> 8 #include<map> 9 using namespace std; 10 11 const int ONE=1200005; 12 const int INF=2147483640; 13 14 map <int,int> a[ONE]; 15 16 int n,ch[ONE]; 17 int len[ONE],fa[ONE]; 18 19 int get() 20 { 21 int res=1,Q=1;char c; 22 while( (c=getchar())<48 || c>57 ) 23 if(c=='-')Q=-1; 24 res=c-48; 25 while( (c=getchar())>=48 && c<=57 ) 26 res=res*10+c-48; 27 return res*Q; 28 } 29 30 struct SAM 31 { 32 int last, cnt; 33 SAM() {last = cnt = 1;} 34 void Add(int c) 35 { 36 int x = last, New = last = ++cnt; 37 len[New] = len[x] + 1; 38 while(x && !a[x][c]) a[x][c] = New, x = fa[x]; 39 if(!x) {fa[New] = 1; return;} 40 41 int q = a[x][c]; 42 if(len[q] == len[x] + 1) fa[New] = q; 43 else 44 { 45 int Nq = ++cnt; len[Nq] = len[x] + 1; 46 a[Nq] = a[q]; 47 fa[Nq] = fa[q]; 48 fa[New] = fa[q] = Nq; 49 while(a[x][c] == q) a[x][c] = Nq, x = fa[x]; 50 } 51 } 52 53 void Run() 54 { 55 map <int,int>::iterator it; 56 int x = 1; 57 for(int i=1; i<=n; i++) 58 { 59 it = a[x].begin(); 60 x = it->second; 61 if(i!=n) printf("%d ", it->first); 62 else printf("%d", it->first); 63 } 64 } 65 }S; 66 67 int main() 68 { 69 n = get(); 70 for(int i=1; i<=n; i++) ch[i] = get(); 71 for(int i=1; i<=n*2; i++) i<=n ? S.Add(ch[i]):S.Add(ch[i-n]); 72 73 S.Run(); 74 }