【Learning】适妞来学SA
来源:互联网 发布:苏州淘宝拍摄 编辑:程序博客网 时间:2024/05/17 05:55
Contest
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=23305#overview
Template
sa[i]=j表示str+i这个字符串在所有后缀中第j小
rank[i]=j表示后缀中第i小的是str+j
rank[i]=j表示后缀中第i小的是str+j
const int N = 5e4 + 9;namespace Suffix_array{ # define F(x) ((x)/3+((x)%3==1?0:tb)) # define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2) int wa[N * 3] , wb[N * 3] , wv[N * 3] , ws[N * 3]; int c0(int *r, int a, int b){ return r[a] == r[b] && r[a + 1] == r[b + 1] && r[a + 2] == r[b + 2]; } int c12(int k, int *r, int a, int b){ if (k == 2) return r[a] < r[b] || r[a] == r[b] && c12(1, r, a + 1, b + 1); else return r[a] < r[b] || r[a] == r[b] && wv[a + 1] < wv[b + 1]; } void sort(int *r, int *a, int *b, int n, int m) { int i; for (i = 0; i < n; i++) wv[i] = r[a[i]]; for (i = 0; i < m; i++) ws[i] = 0; for (i = 0; i < n; i++) ws[wv[i]]++; for (i = 1; i < m; i++) ws[i] += ws[i-1]; for (i = n-1; i >= 0; i--) b[--ws[wv[i]]] = a[i]; return; } void dc3(int *r, int *sa, int n, int m) { int i, j, *rn = r + n; int *san = sa + n, ta = 0, tb = (n + 1) / 3, tbc = 0, p; r[n] = r[n + 1] = 0; for (i = 0; i < n; i++) if (i % 3 != 0) wa[tbc++] = i; sort(r + 2, wa, wb, tbc, m); sort(r + 1, wb, wa, tbc, m); sort(r, wa, wb, tbc, m); for (p = 1, rn[F(wb[0])] = 0, i = 1; i < tbc; i++) rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p-1 : p++; if (p < tbc) dc3(rn, san, tbc, p); else for (i = 0; i < tbc; i++) san[rn[i]] = i; for (i = 0; i < tbc; i++) if (san[i] < tb) wb[ta++] = san[i] * 3; if (n % 3 == 1) wb[ta++] = n-1; sort(r, wb, wa, ta, m); for (i = 0; i < tbc; i++) wv[wb[i] = G(san[i])] = i; for (i = 0, j = 0, p = 0; i < ta && j < tbc; p++) sa[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++]; for (; i < ta; p++) sa[p] = wa[i++]; for (; j < tbc; p++) sa[p] = wb[j++]; } //str 和sa 也要三倍 // str 最小是 1 void da(int str[],int sa[],int rank[],int height[],int n,int m) { for (int i = n; i < n * 3; i++) str[i] = 0; dc3 (str , sa , n + 1 , m); int i, j, k; for (i = 0; i < n; i++){ sa[i] = sa[i + 1]; rank[sa[i]] = i; } for (i = 0, j = 0, k = 0; i < n; height[rank[i ++]] = k) if (rank[i] > 0) for (k ? k--: 0 , j = sa[rank[i]-1]; i + k < n && j + k < n && str[i + k] == str[j + k]; k++); }}using namespace Suffix_array;int A[N] , rank[N] , sa[N] , height[N] , Case;char str[N];int f[N][20];int lent[N];void lcpinit(int len){ int i , j; int n = len , k = 1 , l = 0; RST(f); // 不明白 for(i = 0 ; i < n; ++i){ f[i][0] = height[i]; if (i + 1 > k * 2){ k <<= 1; l++; } lent[i + 1] = l; } for(j = 1; (1 << j) - 1 < n ; j++) for(i = 0 ; i + (1 << j) < n ; i++) f[i][j] = min(f[i][j - 1] , f[i + (1 << (j - 1))][j - 1]);}int lcp(int x , int y){ x = rank[x] , y = rank[y]; if (x > y) swap(x , y); if (x == y) return x - sa[x]; x++; int k = lent[y - x + 1]; return min(f[x][k] , f[y - (1 << k) + 1][k]);}
Step
A Musical Theme
做差,求sa 之后二分+判断
#include <functional>#include <algorithm>#include <iostream>#include <fstream>#include <sstream>#include <iomanip>#include <numeric>#include <cstring>#include <cassert>#include <cstdio>#include <string>#include <vector>#include <bitset>#include <queue>#include <stack>#include <cmath>#include <ctime>#include <list>#include <set>#include <map>using namespace std;#define DO(n) for ( int ____n ## __line__ = n; ____n ## __line__ -- ; )#define ALL(A) A.begin(), A.end()#define BSC(A, x) (lower_bound(ALL(A), x) - A.begin())#define CTN(T, x) (T.find(x) != T.end())#define SZ(A) int(A.size())#define PB push_back#define MP(A, B) make_pair(A, B)#define fi first#define se secondtypedef long long LL;typedef vector<int> VI;typedef map<int, int> MII;typedef pair<int, int> PII;typedef pair<LL, LL> PLL;template<class T> inline void RST(T &A){memset(A, 0, sizeof(A));}template<class T> inline void FLC(T &A, int x){memset(A, x, sizeof(A));}template<class T> inline void CLR(T &A){A.clear();}//}/** Constant List .. **/ //{const int dx4[] = {-1, 0, 1, 0};const int dy4[] = {0, 1, 0, -1};const int dx8[] = {-1, 0, 1, 0 , -1 , -1 , 1 , 1};const int dy8[] = {0, 1, 0, -1 , -1 , 1 , -1 , 1};const int dxhorse[] = {-2 , -2 , -1 , -1 , 1 , 1 , 2 , 2};const int dyhorse[] = {1 , -1 , 2 , -2 , 2 ,-2 , 1 ,-1};const int MOD = 1000000007;//int MOD = 99990001;const int INF = 0x3f3f3f3f;const LL INFF = 1LL << 60;const double EPS = 1e-9;const double OO = 1e15;const double PI = acos(-1.0); //M_PI;//}template<class T> inline void checkMin(T &a,const T b){if (b<a) a=b;}template<class T> inline void checkMax(T &a,const T b){if (a<b) a=b;}//}template<class T> inline T low_bit(T x) {return x & -x;}/*****************************************************************/const int N = 3e5+10;namespace Suffix_array{ # define F(x) ((x)/3+((x)%3==1?0:tb)) # define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2) int wa[N * 3] , wb[N * 3] , wv[N * 3] , ws[N * 3]; int c0(int *r, int a, int b){ return r[a] == r[b] && r[a + 1] == r[b + 1] && r[a + 2] == r[b + 2]; } int c12(int k, int *r, int a, int b){ if (k == 2) return r[a] < r[b] || r[a] == r[b] && c12(1, r, a + 1, b + 1); else return r[a] < r[b] || r[a] == r[b] && wv[a + 1] < wv[b + 1]; } void sort(int *r, int *a, int *b, int n, int m) { int i; for (i = 0; i < n; i++) wv[i] = r[a[i]]; for (i = 0; i < m; i++) ws[i] = 0; for (i = 0; i < n; i++) ws[wv[i]]++; for (i = 1; i < m; i++) ws[i] += ws[i-1]; for (i = n-1; i >= 0; i--) b[--ws[wv[i]]] = a[i]; return; } void dc3(int *r, int *sa, int n, int m) { int i, j, *rn = r + n; int *san = sa + n, ta = 0, tb = (n + 1) / 3, tbc = 0, p; r[n] = r[n + 1] = 0; for (i = 0; i < n; i++) if (i % 3 != 0) wa[tbc++] = i; sort(r + 2, wa, wb, tbc, m); sort(r + 1, wb, wa, tbc, m); sort(r, wa, wb, tbc, m); for (p = 1, rn[F(wb[0])] = 0, i = 1; i < tbc; i++) rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p-1 : p++; if (p < tbc) dc3(rn, san, tbc, p); else for (i = 0; i < tbc; i++) san[rn[i]] = i; for (i = 0; i < tbc; i++) if (san[i] < tb) wb[ta++] = san[i] * 3; if (n % 3 == 1) wb[ta++] = n-1; sort(r, wb, wa, ta, m); for (i = 0; i < tbc; i++) wv[wb[i] = G(san[i])] = i; for (i = 0, j = 0, p = 0; i < ta && j < tbc; p++) sa[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++]; for (; i < ta; p++) sa[p] = wa[i++]; for (; j < tbc; p++) sa[p] = wb[j++]; } //str 和sa 也要三倍 // str 最小是 1 void da(int str[],int sa[],int rank[],int height[],int n,int m) { for (int i = n; i < n * 3; i++) str[i] = 0; dc3 (str , sa , n + 1 , m); int i, j, k; for (i = 0; i < n; i++){ sa[i] = sa[i + 1]; rank[sa[i]] = i; } for (i = 0, j = 0, k = 0; i < n; height[rank[i ++]] = k) if (rank[i] > 0) for (k ? k--: 0 , j = sa[rank[i]-1]; i + k < n && j + k < n && str[i + k] == str[j + k]; k++); }}using namespace Suffix_array;//int f[N][20];//int lent[N];//void lcpinit(int len){// int i , j;// int n = len , k = 1 , l = 0;
// RST(f); /// 不明白。。。。// for(i = 0 ; i < n; ++i){// f[i][0] = height[i];// if (i + 1 > k * 2){// k <<= 1;// l++;// }// lent[i + 1] = l;// }// for(j = 1; (1 << j) - 1 < n ; j++)// for(i = 0 ; i + (1 << j) < n ; i++)// f[i][j] = min(f[i][j - 1] , f[i + (1 << (j - 1))][j - 1]);//}//int lcp(int x , int y){// if (x > y) swap(x , y);// if (x == y) return x - sa[x];// x++;// int k = lent[y - x + 1];// return min(f[x][k] , f[y - (1 << k) + 1][k]);//}int n;int A[N] , sa[N * 3], rank[N * 3] , height[N * 3];bool check(int x){ int low = sa[0] , high = sa[0]; for (int i = 1; i < n; ++i){ if (height[i] >= x){ checkMin(low , sa[i]); checkMax(high , sa[i]); if (high - low >= x) return true; } else{ low = sa[i]; high = sa[i]; } } return false;}void solve(){ for (int i = 0 ; i < n; ++i) scanf("%d" , &A[i]); int o = 1; for (int i = 0; i < n - 1 ; ++i){ A[i] = A[i] - A[i + 1]; checkMin(o , A[i]); } n--; for (int i = 0 ; i < n ; ++i) { A[i] -= o - 1;// printf("%d " , A[i]); }// puts(""); da(A , sa , rank , height , n , 256);// for (int i = 0 ; i <= n; ++i) cout<< height[i] << endl; int low = 0 , high = n , ans = low , mid; do{ mid = low + high >> 1; if (check(mid)){ checkMax(ans , mid); low = mid + 1; } else high = mid - 1; }while(low <= high); if (ans < 4) puts("0"); else printf("%d\n" , ans + 1);}int main(){ while(~scanf("%d" , &n) , n) solve();}
B Milk Patterns
可以二分 + 验证
我用 lcp 正好验证一下模板
#include <functional>#include <algorithm>#include <iostream>#include <fstream>#include <sstream>#include <iomanip>#include <numeric>#include <cstring>#include <cassert>#include <cstdio>#include <string>#include <vector>#include <bitset>#include <queue>#include <stack>#include <cmath>#include <ctime>#include <list>#include <set>#include <map>using namespace std;#define DO(n) for ( int ____n ## __line__ = n; ____n ## __line__ -- ; )#define ALL(A) A.begin(), A.end()#define BSC(A, x) (lower_bound(ALL(A), x) - A.begin())#define CTN(T, x) (T.find(x) != T.end())#define SZ(A) int(A.size())#define PB push_back#define MP(A, B) make_pair(A, B)#define fi first#define se secondtypedef long long LL;typedef vector<int> VI;typedef map<int, int> MII;typedef pair<int, int> PII;typedef pair<LL, LL> PLL;template<class T> inline void RST(T &A){memset(A, 0, sizeof(A));}template<class T> inline void FLC(T &A, int x){memset(A, x, sizeof(A));}template<class T> inline void CLR(T &A){A.clear();}//}/** Constant List .. **/ //{const int dx4[] = {-1, 0, 1, 0};const int dy4[] = {0, 1, 0, -1};const int dx8[] = {-1, 0, 1, 0 , -1 , -1 , 1 , 1};const int dy8[] = {0, 1, 0, -1 , -1 , 1 , -1 , 1};const int dxhorse[] = {-2 , -2 , -1 , -1 , 1 , 1 , 2 , 2};const int dyhorse[] = {1 , -1 , 2 , -2 , 2 ,-2 , 1 ,-1};const int MOD = 1000000007;//int MOD = 99990001;const int INF = 0x3f3f3f3f;const LL INFF = 1LL << 60;const double EPS = 1e-9;const double OO = 1e15;const double PI = acos(-1.0); //M_PI;//}template<class T> inline void checkMin(T &a,const T b){if (b<a) a=b;}template<class T> inline void checkMax(T &a,const T b){if (a<b) a=b;}//}template<class T> inline T low_bit(T x) {return x & -x;}/*****************************************************************/const int N = 3e5+10;namespace Suffix_array{ # define F(x) ((x)/3+((x)%3==1?0:tb)) # define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2) int wa[N * 3] , wb[N * 3] , wv[N * 3] , ws[N * 3]; int c0(int *r, int a, int b){ return r[a] == r[b] && r[a + 1] == r[b + 1] && r[a + 2] == r[b + 2]; } int c12(int k, int *r, int a, int b){ if (k == 2) return r[a] < r[b] || r[a] == r[b] && c12(1, r, a + 1, b + 1); else return r[a] < r[b] || r[a] == r[b] && wv[a + 1] < wv[b + 1]; } void sort(int *r, int *a, int *b, int n, int m) { int i; for (i = 0; i < n; i++) wv[i] = r[a[i]]; for (i = 0; i < m; i++) ws[i] = 0; for (i = 0; i < n; i++) ws[wv[i]]++; for (i = 1; i < m; i++) ws[i] += ws[i-1]; for (i = n-1; i >= 0; i--) b[--ws[wv[i]]] = a[i]; return; } void dc3(int *r, int *sa, int n, int m) { int i, j, *rn = r + n; int *san = sa + n, ta = 0, tb = (n + 1) / 3, tbc = 0, p; r[n] = r[n + 1] = 0; for (i = 0; i < n; i++) if (i % 3 != 0) wa[tbc++] = i; sort(r + 2, wa, wb, tbc, m); sort(r + 1, wb, wa, tbc, m); sort(r, wa, wb, tbc, m); for (p = 1, rn[F(wb[0])] = 0, i = 1; i < tbc; i++) rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p-1 : p++; if (p < tbc) dc3(rn, san, tbc, p); else for (i = 0; i < tbc; i++) san[rn[i]] = i; for (i = 0; i < tbc; i++) if (san[i] < tb) wb[ta++] = san[i] * 3; if (n % 3 == 1) wb[ta++] = n-1; sort(r, wb, wa, ta, m); for (i = 0; i < tbc; i++) wv[wb[i] = G(san[i])] = i; for (i = 0, j = 0, p = 0; i < ta && j < tbc; p++) sa[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++]; for (; i < ta; p++) sa[p] = wa[i++]; for (; j < tbc; p++) sa[p] = wb[j++]; } //str 和sa 也要三倍 // str 最小是 1 void da(int str[],int sa[],int rank[],int height[],int n,int m) { for (int i = n; i < n * 3; i++) str[i] = 0; dc3 (str , sa , n + 1 , m); int i, j, k; for (i = 0; i < n; i++){ sa[i] = sa[i + 1]; rank[sa[i]] = i; } for (i = 0, j = 0, k = 0; i < n; height[rank[i ++]] = k) if (rank[i] > 0) for (k ? k--: 0 , j = sa[rank[i]-1]; i + k < n && j + k < n && str[i + k] == str[j + k]; k++); }}using namespace Suffix_array;int n;int A[N] , sa[N * 3], rank[N * 3] , height[N * 3];int f[N][20];int lent[N];void lcpinit(int len){ int i , j; int n = len , k = 1 , l = 0; for(i = 0 ; i < n; ++i){ f[i][0] = height[i]; if (i + 1 > k * 2){ k <<= 1; l++; } lent[i + 1] = l; } for(j = 1; (1 << j) - 1 < n ; j++) for(i = 0 ; i + (1 << j) - 1 < n ; i++) f[i][j] = min(f[i][j - 1] , f[i + (1 << (j - 1))][j - 1]);}int lcp(int x , int y){ if (x > y) swap(x , y); if (x == y) return x - sa[x]; x++; int k = lent[y - x + 1]; return min(f[x][k] , f[y - (1 << k) + 1][k]);}int K;void solve(){ for (int i = 0 ; i < n; ++i) scanf("%d" , &A[i]);// puts(""); da(A , sa , rank , height , n , 256);// for (int i = 0 ; i <= n; ++i) cout<< sa[i] << endl; lcpinit(n ); int ans = 0; for (int i = 0 ; i + K - 1 < n ; ++i){// printf("%d %d\n", i , lcp(i , i + K - 2)); checkMax(ans , lcp(i , i + K - 1)); } printf("%d\n" , ans);}int main(){ while(~scanf("%d%d" , &n , &K)) solve();}
E Palindrome
求最长回文串,如果有多个输出第一个。。
注意 ABCDEFDCBA 答案不是 ABCD 的问题。。
于是乎要对于 sa 的位置做个判断
#include <functional>#include <algorithm>#include <iostream>#include <fstream>#include <sstream>#include <iomanip>#include <numeric>#include <cstring>#include <cassert>#include <cstdio>#include <string>#include <vector>#include <bitset>#include <queue>#include <stack>#include <cmath>#include <ctime>#include <list>#include <set>#include <map>using namespace std;#define DO(n) for ( int ____n ## __line__ = n; ____n ## __line__ -- ; )#define ALL(A) A.begin(), A.end()#define BSC(A, x) (lower_bound(ALL(A), x) - A.begin())#define CTN(T, x) (T.find(x) != T.end())#define SZ(A) int(A.size())#define PB push_back#define MP(A, B) make_pair(A, B)#define fi first#define se secondtypedef long long LL;typedef vector<int> VI;typedef map<int, int> MII;typedef pair<int, int> PII;typedef pair<LL, LL> PLL;template<class T> inline void RST(T &A){memset(A, 0, sizeof(A));}template<class T> inline void FLC(T &A, int x){memset(A, x, sizeof(A));}template<class T> inline void CLR(T &A){A.clear();}//}/** Constant List .. **/ //{const int dx4[] = {-1, 0, 1, 0};const int dy4[] = {0, 1, 0, -1};const int dx8[] = {-1, 0, 1, 0 , -1 , -1 , 1 , 1};const int dy8[] = {0, 1, 0, -1 , -1 , 1 , -1 , 1};const int dxhorse[] = {-2 , -2 , -1 , -1 , 1 , 1 , 2 , 2};const int dyhorse[] = {1 , -1 , 2 , -2 , 2 ,-2 , 1 ,-1};const int MOD = 1000000007;//int MOD = 99990001;const int INF = 0x3f3f3f3f;const LL INFF = 1LL << 60;const double EPS = 1e-9;const double OO = 1e15;const double PI = acos(-1.0); //M_PI;//}template<class T> inline void checkMin(T &a,const T b){if (b<a) a=b;}template<class T> inline void checkMax(T &a,const T b){if (a<b) a=b;}//}template<class T> inline T low_bit(T x) {return x & -x;}/*****************************************************************/const int N = 3e5+10;namespace Suffix_array{ # define F(x) ((x)/3+((x)%3==1?0:tb)) # define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2) int wa[N * 3] , wb[N * 3] , wv[N * 3] , ws[N * 3]; int c0(int *r, int a, int b){ return r[a] == r[b] && r[a + 1] == r[b + 1] && r[a + 2] == r[b + 2]; } int c12(int k, int *r, int a, int b){ if (k == 2) return r[a] < r[b] || r[a] == r[b] && c12(1, r, a + 1, b + 1); else return r[a] < r[b] || r[a] == r[b] && wv[a + 1] < wv[b + 1]; } void sort(int *r, int *a, int *b, int n, int m) { int i; for (i = 0; i < n; i++) wv[i] = r[a[i]]; for (i = 0; i < m; i++) ws[i] = 0; for (i = 0; i < n; i++) ws[wv[i]]++; for (i = 1; i < m; i++) ws[i] += ws[i-1]; for (i = n-1; i >= 0; i--) b[--ws[wv[i]]] = a[i]; return; } void dc3(int *r, int *sa, int n, int m) { int i, j, *rn = r + n; int *san = sa + n, ta = 0, tb = (n + 1) / 3, tbc = 0, p; r[n] = r[n + 1] = 0; for (i = 0; i < n; i++) if (i % 3 != 0) wa[tbc++] = i; sort(r + 2, wa, wb, tbc, m); sort(r + 1, wb, wa, tbc, m); sort(r, wa, wb, tbc, m); for (p = 1, rn[F(wb[0])] = 0, i = 1; i < tbc; i++) rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p-1 : p++; if (p < tbc) dc3(rn, san, tbc, p); else for (i = 0; i < tbc; i++) san[rn[i]] = i; for (i = 0; i < tbc; i++) if (san[i] < tb) wb[ta++] = san[i] * 3; if (n % 3 == 1) wb[ta++] = n-1; sort(r, wb, wa, ta, m); for (i = 0; i < tbc; i++) wv[wb[i] = G(san[i])] = i; for (i = 0, j = 0, p = 0; i < ta && j < tbc; p++) sa[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++]; for (; i < ta; p++) sa[p] = wa[i++]; for (; j < tbc; p++) sa[p] = wb[j++]; } //str 和sa 也要三倍 // str 最小是 1 void da(int str[],int sa[],int rank[],int height[],int n,int m) { for (int i = n; i < n * 3; i++) str[i] = 0; dc3 (str , sa , n + 1 , m); int i, j, k; for (i = 0; i < n; i++){ sa[i] = sa[i + 1]; rank[sa[i]] = i; } for (i = 0, j = 0, k = 0; i < n; height[rank[i ++]] = k) if (rank[i] > 0) for (k ? k--: 0 , j = sa[rank[i]-1]; i + k < n && j + k < n && str[i + k] == str[j + k]; k++); }}using namespace Suffix_array;//int f[N][20];//int lent[N];//void lcpinit(int len){// int i , j;// int n = len , k = 1 , l = 0;// for(i = 0 ; i < n; ++i){// f[i][0] = height[i];// if (i + 1 > k * 2){// k <<= 1;// l++;// }// lent[i + 1] = l;// }// for(j = 1; (1 << j) - 1 < n ; j++)// for(i = 0 ; i + (1 << j) < n ; i++)// f[i][j] = min(f[i][j - 1] , f[i + (1 << (j - 1))][j - 1]);//}//int lcp(int x , int y){// if (x > y) swap(x , y);// if (x == y) return x - sa[x];// x++;// int k = lent[y - x + 1];// return min(f[x][k] , f[y - (1 << k) + 1][k]);//}int A[N] , rank[N] , sa[N] , height[N];char str[N];void solve(){ int n = strlen(str); int m = n; str[n++] = '$'; for (int i = 0 ; i < m ; ++i) str[n++] = str[m - i - 1]; str[n++] = 0; for (int i = 0 ; i < n ; ++i) A[i] = str[i]; da(A , sa , rank , height , n , 256); int ans = 0 , now = INF; for (int i = 1 ; i < n; ++i){ //cout << height[i] << endl; if (sa[i - 1] < m && sa[i] > m || sa[i - 1] > m && sa[i] < m){ int p = sa[i - 1] , q = sa[i];// if (p > m) p -= m;// if (q > m) q -= m; p += height[i] - 1;// printf("%d-%d-%d\n" , p , m , q); if (m * 2 != p + q) continue; if (height[i] > ans){ ans = height[i]; now = min(sa[i - 1] , sa[i]); } else if (height[i] == ans){ //cout << min(sa[i - 1] , sa[i]) << endl; checkMin(now , min(sa[i - 1] , sa[i])); } } } //cout << ans << endl; if (ans == 1) putchar(str[0]); else for (int i = 0 ; i < ans ; ++i) putchar(str[now + i]); puts("");}int main(){ while(~scanf("%s" , str))solve();}
G - Maximum repetition substring
求字典序最小的 重复次数最多的 子串。。。
好难的一个题目。
int A[N] , rank[N] , sa[N] , height[N] , Case;char str[N];int f[N][20];int lent[N];void lcpinit(int len){ int i , j; int n = len , k = 1 , l = 0; for(i = 0 ; i < n; ++i){ f[i][0] = height[i]; if (i + 1 > k * 2){ k <<= 1; l++; } lent[i + 1] = l; } for(j = 1; (1 << j) - 1 < n ; j++) for(i = 0 ; i + (1 << j) < n ; i++) f[i][j] = min(f[i][j - 1] , f[i + (1 << (j - 1))][j - 1]);}int lcp(int x , int y){ x = rank[x] , y = rank[y]; if (x > y) swap(x , y); if (x == y) return x - sa[x]; x++; int k = lent[y - x + 1]; return min(f[x][k] , f[y - (1 << k) + 1][k]);}void solve(){ printf("Case %d: " , ++Case); int n = strlen(str); for (int i = 0 ; i < n ; ++i) A[i] = str[i]; da(A , sa , rank , height , n , 256); lcpinit(n); VI ans; ans.clear(); int mx = -1; for (int L = 1 ; L < n ; ++L){ for (int i = 0 ; i + L < n ; i += L){ int K = lcp(i , i + L); int R = K / L + 1; int t = L - K % L; t = i - t; if (t >= 0 && K % L != 0){ if (lcp(t , t + L) >= K) R++; } if (R > mx){ ans.clear(); mx = R; ans.PB(L); } if (R == mx) ans.PB(L); } }// cout << ans.size() <<endl; int start , b = 0 , c = 0; for (int i = 0 ; i < n && !b ; ++i){ for (int j = 0 ; j < ans.size() ; ++j){ int tl = ans[j]; if (lcp(sa[i] , sa[i] + tl) >= (mx - 1) * tl){ start = sa[i]; c = tl * mx; b = 1; break; } } }// cout << c << endl; for (int i = 0 ; i < c ; ++i) putchar(str[start + i]); puts("");}int main(){ Case = 0; while(~scanf("%s" , str) , str[0] != '#')solve();}
L - Life Forms
把这题 1Y 了爽爽爽。。。
这题绝对能增加对于 SA 的理解好么。。。
题意: 多字符串,求所有 在 > n/2 串中出现的公共子串,字典序输出。
解法:
全部连起来,二分答案。利用两个 vector 滚动求解。
要注意的是——一定要用 sa[i] 不是 sa[i - 1] 也不是 i
int belongs[N * 3];int END[N];char str[N];int n , m;bool occupy[200];int usesolve;VI out[2];bool check(int len){ int sum = 1; RST(occupy); occupy[belongs[sa[0]]] = 1; out[usesolve].clear(); for (int i = 1 ; i < m ; ++i){ if (height[i] >= len){ if (!occupy[belongs[sa[i]]]){ occupy[belongs[sa[i]]] = 1; ++sum; } } else{ if (sum * 2 > n) out[usesolve].PB(sa[i - 1]); sum = 1; RST(occupy); occupy[belongs[sa[i]]] = 1; } } if (sum * 2 > n) out[usesolve].PB(sa[m - 1]); return SZ(out[usesolve]);}int ans;void output(){ usesolve ^= 1; int sz = SZ(out[usesolve]); for (int i = 0 ; i < sz ; ++i){ for (int j = 0 ; j < ans ; ++j) printf("%c" , A[j + out[usesolve][i]]); puts(""); }}void makebelongs(){ for (int i = 0 ; i < m ; ++i){ int res = lower_bound(END , END + n + 1 , sa[i]) - END; belongs[sa[i]] = res; }}void solve(){ m = 0; out[0].clear() , out[1].clear(); usesolve = 0; for (int i = 0 ; i < n ; ++i){ scanf("%s" , str); int len = strlen(str); for (int j = 0 ; j < len ; ++j) A[ m ++ ] = str[j]; END[i] = m; A[ m ++ ] = max( 'Z' , 'z' ) + 1 + i; } da(A , sa , rank , height , m , 256); END[n] = INF; makebelongs(); int low = 0 , high = m , mid; ans = 0 ; do{ mid = low + high >> 1; if (check(mid)){ if (ans < mid){ usesolve ^= 1; ans = mid; } low = mid + 1; } else high = mid - 1; }while(low <= high); if (ans == 0){ puts("?"); return; } output();}int main(){// freopen("0.in" , "r" , stdin); bool first = true; while(scanf("%d" , &n) , n){ if (!first) puts(""); first = false; solve(); }}
K - Common Substrings
题意:
求公共子串对数。
解法:
连起来,DA 。 利用单调栈[记录一个pair<LCP , cnt>] 来维护。
先用 A 扫 B 再用 B 扫 A。
具体虽然 AC 了还不是很明白,[[[[ height[i + 1] 的原因。。。
先贴代码日后想
namespace List{ PLL st[N]; LL sum; int top; void init(){ top = 0; sum = 0; } void push(LL x , LL cnt){ if (x <= 0){ top = 0; sum = 0; cnt = 0; return; } sum += x * cnt; while(top && st[top - 1].fi >= x){ sum -= (st[top - 1].fi - x) * st[top - 1].se; cnt += st[top - 1].se; top--; } st[top].fi = x; st[top].se = cnt; top++; }};int belongs[N * 3];int k;char str[N];int lenpre , m;void makebelongs(){ for (int i = 0 ; i < m ; ++i) if (sa[i] <= lenpre) belongs[sa[i]] = 0; else belongs[sa[i]] = 1;}void solve(){ scanf("%s", str); int len = strlen(str); m = 0; for (int i = 0 ; i < len ; ++i) A[m++] = str[i]; A[m++] = '$'; lenpre = m - 1; scanf("%s" , str); for (int i = 0 ; i < len ; ++i) A[m++] = str[i]; da(A , sa , rank , height , m , 256); height[m] = 0; makebelongs(); LL ans = 0; /** A 扫 B */ List :: init(); for (int i = 1 ; i < m ; ++i){ if (belongs[sa[i]] == 1) ans += List :: sum; if (belongs[sa[i]] == 0) List :: push(height[i + 1] - k + 1 , 1); if (belongs[sa[i]] == 1) List :: push(height[i + 1] - k + 1 , 0); } /** B 扫 A */ List :: init(); for (int i = 1 ; i < m ; ++i){ if (belongs[sa[i]] == 0) ans += List :: sum; if (belongs[sa[i]] == 1) List :: push(height[i + 1] - k + 1 , 1); if (belongs[sa[i]] == 0) List :: push(height[i + 1] - k + 1 , 0); } printf("%I64d\n" , ans);}int main(){// freopen("0.in" , "r" , stdin);// freopen("0.out" , "w" , stdout); while(scanf("%d" , &k) , k) solve();}
总结:
SA 好神奇!马上要到赛季了,加油思密达!!!
- 【Learning】适妞来学SA
- SA
- sa
- sa
- sa
- sa
- sa
- sa
- sa
- SA
- sa
- sa
- sa
- sa
- sa
- sa
- sa
- sa
- Ubuntu 10.10 apt-get update解决办法
- 学会系统思维
- makefile的一点注意点。关于一行和不是一行的当前的路径。
- C++入门--3.0复合类型
- MySQL 运行状态及调优(二)
- 【Learning】适妞来学SA
- ADR的结构
- 金字塔 下面代码的目标是输出一个大写字母组成的金字塔。 其中space表示金字塔底距离左边的空白长度,x表示金字塔底的中心字母。
- Java和JSP几个常见问题
- 希尔排序(shell排序)的详细解说,对插入排序算法的改进
- hdu 2601 An easy problem
- Windows系统Vim编辑器乱码解决分析
- 《Expert MySQL》翻译——chapter2.解剖数据库系统(3)
- hdu1017