暑假集训 || 后缀三连

orz……

后缀数组orz……

例如:n = 8;

num[] = { 1, 1, 2, 1, 1, 1, 1, 2, $ }; 注意 num 最后一位为 0,其他 大于 0
rank[] = 4, 6, 8, 1, 2, 3, 5, 7, 0 ;rank[0 n-1] 为有效值,rank[n] 必定为 0 无效值
sa[] = 8, 3, 4, 5, 0, 6, 1, 7, 2 ;sa[1 n] 为有效值,sa[0] 必定为 n 是 无效值
height[]= 0, 0, 3, 2, 3, 1, 2, 0, 1 ;height[2 n] 为有效值

const int maxn = 100010;
int t1[maxn], t2[maxn], c[maxn];
bool cmp(int *r, int a, int b, int l)
{
    return r[a] == r[b] && r[a+l] == r[b+l];
}
void da(int str[], int sa[], int rank[], int height[], int n, int m)
{
    n++;
    int p, *x = t1, *y = t2;
    for(int i = 0; i < m; i++) c[i] = 0;
    for(int i = 0; i < n; i++) c[x[i] = str[i]]++;
    for(int i = 1; i < m; i++) c[i] += c[i-1];
    for(int i = n-1; i >= 0; i--) sa[--c[x[i]]] = i;
    for(int j = 1; j <= n; j <<= 1)
    {
        p = 0;
        for(int i = n-j; i < n; i++) y[p++] = i;
        for(int i = 0; i < n; i++)
            if(sa[i] >= j)
                y[p++] = sa[i] - j;
        for(int i = 0; i < m; i++) c[i] = 0;
        for(int i = 0; i < n; i++) c[x[y[i]]]++;
        for(int i = 1; i < m; i++) c[i] += c[i-1];
        for(int i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
        swap(x, y);
        p = 1, x[sa[0]] = 0;
        for(int i = 1; i < n; i++)
            x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;
        if(p >= n) break;
        m = p;
    }
    int k = 0;
    n--;
    for(int i = 0; i <= n; i++) rank[sa[i]] = i;
    for(int i = 0; i < n; i++)
    {
        if(k) k--;
        int j = sa[rank[i]-1];
        while(str[i+k] == str[j+k]) k++;
        height[rank[i]] = k;
    }
}
int rank[maxn], height[maxn], h[maxn];
int RMQ[maxn], mm[maxn];
int best[20][maxn];
void initRMQ(int n)
{
    mm[0] = -1;
    for(int i = 1; i <= n; i++)
        mm[i] = ((i & (i-1)) == 0) ? mm[i-1]+1 : mm[i-1];
    for(int i = 1; i <= n; i++) best[0][i] = i;
    for(int i = 1; i <= mm[n]; i++)
        for(int j = 1; j + (1<<i) - 1 <= n; j++)
        {
            int a = best[i-1][j];
            int b = best[i-1][j + (1 << (i-1))];
            if(RMQ[a] < RMQ[b]) best[i][j] = a;
            else best[i][j] = b;
        }
}
int askRMQ(int a, int b)
{
    int t;
    t = mm[b-a+1];
    b -= (1<<t) - 1;
    a = best[t][a], b = best[t][b];
    return RMQ[a] < RMQ[b] ? a : b;
}
int lcp(int a, int b)
{
    a = rank[a], b = rank[b];
    if(a > b) swap(a, b);
    return height[askRMQ(a+1, b)];
}
View Code

题意:给一个字符串,以每一位为开头环形的读,把len种读法排序,排序后每种读法最后一位连在一起就是答案

思路:把数组接一段在后面,sa[i]的前一位就是排序后的最后一位。。

int main()
{
    scanf(" %s", str);
    int len = strlen(str);
    for(int i = 0; i < len; i++) str[i+len] = str[i];
    len = len<<1;
    da(str, sa, rank, height, len, 128);
    int idx = 0;
    for(int i = 1; i <= len; i++)
        if(sa[i] < (len>>1)) ans[idx++] = str[sa[i] + (len>>1) - 1];
    ans[len>>1] = '';
    printf("%s
", ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/pinkglightning/p/9565720.html