【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 
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 好神奇!马上要到赛季了,加油思密达!!!



原创粉丝点击