BZOJ 2882 工艺 (字符串最小循环同构)
题目大意:
给一个长度小于等于30W的数列,求其最小循环同构。
算法讨论:
在自动机长倍长走S后即可。注意这里面是数字,要用map存储。 今天才知道要开四倍长。
Codes:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int L = 300000 + 5; 5 6 int n, a[L<<1], ans; 7 8 struct State{ 9 int len, pre; 10 map <int, int> next; 11 12 State(){ 13 len = pre = 0; 14 next.clear(); 15 } 16 void clear(){ 17 len = pre = 0; 18 next.clear(); 19 } 20 }st[L<<1]; 21 22 struct SuffixAutomaton{ 23 int sz, last; 24 25 void Init(){ 26 last = sz = 0; 27 st[0].len = 0; st[0].pre = -1; 28 sz ++; 29 } 30 void Extend(int c){ 31 int cur = sz ++; 32 st[cur].len = st[last].len + 1; 33 int p; 34 35 for(p = last; p != -1 && !st[p].next[c]; p = st[p].pre) 36 st[p].next[c] = cur; 37 38 if(p == -1) st[cur].pre = 0; 39 else{ 40 int q = st[p].next[c]; 41 if(st[q].len == st[p].len + 1) st[cur].pre = q; 42 else{ 43 int cle = sz ++; 44 st[cle].len = st[p].len + 1; 45 st[cle].pre = st[q].pre; 46 st[cle].next = st[q].next; 47 for(; p != -1 && st[p].next[c] == q; p = st[p].pre) 48 st[p].next[c] = cle; 49 st[q].pre = st[cur].pre = cle; 50 } 51 } 52 last = cur; 53 } 54 }SAM; 55 56 void Input(){ 57 scanf("%d", &n); 58 for(int i = 0; i < n; ++ i) 59 scanf("%d", &a[i]); 60 } 61 void Output(){ 62 bool flag = false; 63 for(int i = ans; i < ans + n; ++ i){ 64 if(!flag){ 65 flag = true; 66 printf("%d", a[i % n]); 67 } 68 else 69 printf(" %d", a[i % n]); 70 } 71 72 printf("\n"); 73 } 74 75 void Solve(){ 76 SAM.Init(); 77 for(int i = 0; i < n; ++ i) 78 a[i + n] = a[i]; 79 for(int i = 0; i < (n<<1); ++ i) 80 SAM.Extend(a[i]); 81 82 int p = 0; 83 map <int, int>:: iterator pos; 84 85 for(int i = 0; i < n; ++ i){ 86 for(pos = st[p].next.begin(); pos != st[p].next.end(); ++ pos){ 87 p = (*pos).second; 88 break; 89 } 90 } 91 92 ans = st[p].len - n; 93 } 94 95 int main(){ 96 97 Input(); 98 Solve(); 99 Output(); 100 101 return 0; 102 }