bzoj 1031 [JSOI2007]字符加密Cipher
题意:给出一个字符串,将所有的循环排列按字典序从小到大排序,并输出最后一个字符
思路:将字符串复制一倍,求出 sa 数组,答案为 s[sa[i] + n - 1](sa[i] < n)。注意数组大小乘 2 !
1 #include <cstdio> 2 #include <string> 3 #include <cstring> 4 5 const int N = 200010; 6 int n, m = 130, x[N], y[N], sa[N], c[N]; 7 char s[N]; 8 9 void get_sa() { 10 for (int i = 0; i < m; ++ i) c[i] = 0; 11 for (int i = 0; i < n; ++ i) ++c[x[i] = s[i]]; 12 for (int i = 1; i < m; ++ i) c[i] += c[i-1]; 13 for (int i = n - 1; i >= 0; -- i) sa[--c[x[i]]] = i; 14 for (int k = 1; k <= n; k <<= 1) { 15 int p = 0; 16 for (int i = n - k; i < n; ++ i) y[p++] = i; 17 for (int i = 0; i < n; ++ i) if (sa[i] >= k) y[p++] = sa[i] - k; 18 for (int i = 0; i < m; ++ i) c[i] = 0; 19 for (int i = 0; i < n; ++ i) ++c[x[y[i]]]; 20 for (int i = 1; i < m; ++ i) c[i] += c[i-1]; 21 for (int i = n - 1; i >= 0; -- i) sa[--c[x[y[i]]]] = y[i]; 22 for (int i = 0; i < n; ++ i) x[i] ^= y[i], y[i] ^= x[i], x[i] ^= y[i]; 23 p = 1, x[sa[0]] = 0; 24 for (int i = 1; i < n; ++ i) 25 x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k] ? p-1 : p++; 26 if (p >= n) break; 27 m = p; 28 } 29 } 30 31 int main() { 32 scanf("%s", s), n = strlen(s); 33 for (int i = 0; i < n; ++ i) s[i+n] = s[i]; 34 int t = n; n *= 2, get_sa(); 35 for (int i = 0; i < n; ++ i) 36 if (sa[i] < t) printf("%c", s[sa[i]+t-1]); 37 puts(""); return 0; 38 }
bzoj 4698 Sdoi2008 Sandy的卡片
题意:求 n 个字符串的最长公共子串
思路:将 n 个字符串拼接成一个串,中间用未出现过且不同的字母分隔(字符ID不限于128),求出 height 后二分。
1 #include <cstdio> 2 #include <string> 3 #include <cstring> 4 5 const int N = 102005, INF = 0x3f3f3f3f; 6 7 int n, m, t; 8 int a[1005][1005], sa[N], c[N], x[N], y[N], s[N]; 9 int rank[N], height[N], vis[N], sta[N], top, id[N]; 10 11 int read() { 12 int x = 0, f = 1; 13 char c = getchar(); 14 while (!isdigit(c)) { 15 if (c == ‘-‘) f = -1; 16 c = getchar(); 17 } 18 while (isdigit(c)) { 19 x = (x << 3) + (x << 1) + (c ^ 48); 20 c = getchar(); 21 } 22 return x * f; 23 } 24 25 int min(int x, int y) { if (x <= y) return x; return y; } 26 int max(int x, int y) { if (x >= y) return x; return y; } 27 28 void getSa() { 29 for (int i = 0; i < m; ++ i) c[i] = 0; 30 for (int i = 0; i < n; ++ i) ++c[x[i] = s[i]]; 31 for (int i = 1; i < m; ++ i) c[i] += c[i-1]; 32 for (int i = n - 1; i >= 0; -- i) sa[--c[x[i]]] = i; 33 34 for (int k = 1; k <= n; k <<= 1) { 35 int p = 0; 36 for (int i = n - k; i < n; ++ i) y[p++] = i; 37 for (int i = 0; i < n; ++ i) if (sa[i] >= k) y[p++] = sa[i] - k; 38 39 for (int i = 0; i < m; ++ i) c[i] = 0; 40 for (int i = 0; i < n; ++ i) ++c[x[y[i]]]; 41 for (int i = 1; i < m; ++ i) c[i] += c[i-1]; 42 for (int i = n - 1; i >= 0; -- i) sa[--c[x[y[i]]]] = y[i]; 43 44 for (int i = 0; i < n; ++ i) x[i] ^= y[i], y[i] ^= x[i], x[i] ^= y[i]; 45 p = 1, x[sa[0]] = 0; 46 for (int i = 1; i < n; ++ i) 47 x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k] ? p-1 : p++; 48 if (p >= n) break; 49 m = p; 50 } 51 } 52 53 void getHeight() { 54 int k = 0; 55 for (int i = 0; i < n; ++ i) rank[sa[i]] = i; 56 for (int i = 0; i < n; ++ i) { 57 if (!rank[i]) continue; 58 if (k) --k; 59 int j = sa[rank[i]-1]; 60 while (i+k < n && j+k < n && s[i+k] == s[j+k]) ++k; 61 height[rank[i]] = k; 62 } 63 } 64 65 bool check(int x) { 66 while (top) vis[sta[top--]] = 0; 67 for (int i = 0; i < n; ++ i) { 68 if (height[i] < x) while(top) vis[sta[top--]] = 0; 69 if (!vis[id[sa[i]]]) { 70 vis[id[sa[i]]] = 1; 71 sta[++top] = id[sa[i]]; 72 if (top == t) return true; 73 } 74 } 75 return false; 76 } 77 78 int main() { 79 freopen("card.in", "r", stdin); 80 freopen("card.out", "w", stdout); 81 82 t = read(); int l = 0, r = INF, minn = INF, maxn = 0; 83 for (int i = 1; i <= t; ++ i) { 84 a[i][0] = read(), a[i][1] = read(); 85 r = min(r, a[i][0] - 1); 86 for (int j = 2; j <= a[i][0]; ++ j) { 87 a[i][j] = read(); 88 minn = min(minn, a[i][j] - a[i][j-1]); 89 maxn = max(maxn, a[i][j] - a[i][j-1]); 90 } 91 } 92 for (int i = 1; i <= t; ++ i) { 93 for (int j = 2; j <= a[i][0]; ++ j) 94 id[n] = i, s[n++] = a[i][j] - a[i][j-1] - minn; 95 s[n++] = ++maxn - minn; 96 } 97 for (int i = 0; i < n; ++ i) m = max(m, s[i] + 1); 98 getSa(), getHeight(); 99 while (l < r) { 100 int mid = l + ((r - l + 1) >> 1); 101 if (check(mid)) l = mid; else r = mid - 1; 102 } 103 printf("%d\n", l + 1); return 0; 104 }