暑假集训 || 后缀三连

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 = 200010;
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(char 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];
char str[maxn], ans[maxn];
int r[maxn], sa[maxn];
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] = '\0';
    printf("%s\n", ans);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/pinkglightning/p/9565720.html