工艺

Time Limit: 10 Sec Memory Limit: 128 MB

Description

小敏和小燕是一对好朋友。
  他们正在玩一种神奇的游戏,叫Minecraft。
  他们现在要做一个由方块构成的长条工艺品。但是方块现在是乱的,而且由于机器的要求,他们只能做到把这个工艺品最左边的方块放到最右边。
  他们想,在仅这一个操作下,最漂亮的工艺品能多漂亮。
  两个工艺品美观的比较方法是,从头开始比较,如果第i个位置上方块不一样那么谁的瑕疵度小,那么谁就更漂亮,如果一样那么继续比较第i+1个方块。如果全都一样,那么这两个工艺品就一样漂亮。

Input

第一行两个整数n,代表方块的数目。
  第二行n个整数,每个整数按从左到右的顺序输出方块瑕疵度的值。

Output

一行n个整数,代表最美观工艺品从左到右瑕疵度的值。

Sample Input

10
 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include<bits/stdc++.h>
using namespace std;

const int ONE=1200005;
const int INF=2147483640;

map <int,int> a[ONE];

int n,ch[ONE];
int len[ONE],fa[ONE];

int get()
{
int res=1,Q=1;char c;
while( (c=getchar())<48 || c>57 )
if(c=='-')Q=-1;
res=c-48;
while( (c=getchar())>=48 && c<=57 )
res=res*10+c-48;
return res*Q;
}

struct SAM
{
int last, cnt;
SAM() {last = cnt = 1;}
void Add(int c)
{
int x = last, New = last = ++cnt;
len[New] = len[x] + 1;
while(x && !a[x][c]) a[x][c] = New, x = fa[x];
if(!x) {fa[New] = 1; return;}

int q = a[x][c];
if(len[q] == len[x] + 1) fa[New] = q;
else
{
int Nq = ++cnt; len[Nq] = len[x] + 1;
a[Nq] = a[q];
fa[Nq] = fa[q];
fa[New] = fa[q] = Nq;
while(a[x][c] == q) a[x][c] = Nq, x = fa[x];
}
}

void Run()
{
map <int,int>::iterator it;
int x = 1;
for(int i=1; i<=n; i++)
{
it = a[x].begin();
x = it->second;
if(i!=n) printf("%d ", it->first);
else printf("%d", it->first);
}
}
}S;

int main()
{
n = get();
for(int i=1; i<=n; i++) ch[i] = get();
for(int i=1; i<=n*2; i++) i<=n ? S.Add(ch[i]):S.Add(ch[i-n]);

S.Run();
}