【Learning】适妞来学SA

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 second

typedef 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 second

typedef 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 second

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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值