UOJ Logo haogram的博客

博客

各路大神帮我看看这份刘汝佳书上的后缀数组倍增代码,#35老是WA

2016-06-25 17:00:30 By haogram

这份代码是《算法竞赛入门经典——训练指南》P221

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define MAXN 100010
using namespace std;
char s[MAXN];
int sa[MAXN], rank[MAXN], height[MAXN];
int wa[MAXN], wb[MAXN], c[MAXN];
int n;

void Build_sa(int m)
{
    int i, *x=wa, *y=wb;
    for(i=0; i<m; i++) c[i] = 0;
    for(i=0; i<n; i++) c[x[i] = s[i]-'a']++;
    for(i=1; i<m; i++) c[i] += c[i-1];
    for(i=n-1; i>=0; i--) sa[--c[x[i]]] = i;
    for(int k=1; k<=n; k<<=1)
    {
        int p = 0;
        for(i=n-k; i<n; i++) y[p++] = i;
        for(i=0; i<n; i++) if(sa[i]>=k) y[p++] = sa[i]-k;
        for(i=0; i<m; i++) c[i] = 0;
        for(i=0; i<n; i++) c[x[y[i]]]++;
        for(i=1; i<m; i++) c[i] += c[i-1];
        for(i=n-1; i>=0; i--) sa[--c[x[y[i]]]] = y[i];
        swap(x,y);
        p = 1; x[sa[0]] = 0;
        for(i=1; i<n; i++)
            x[sa[i]] = (y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k])?p-1:p++;
        m = p;
    }
}

void Build_height()
{
    int k = 0;
    for(int i=0; i<n; i++)
        if(rank[i] > 0)
        {
            if(k) k--;
            int j = sa[rank[i]-1];
            while(s[i+k]==s[j+k]) k++;
            height[rank[i]] = k;
        }
}

int main()
{
    scanf("%s", s);
    n = strlen(s);
    Build_sa(30);
    for(int i=0; i<n; i++) rank[sa[i]] = i;
    s[n] = '$';
    Build_height();
    for(int i=0; i<n; i++) printf("%d ",sa[i]+1); printf("\n");
    for(int i=1; i<n; i++) printf("%d ",height[i]); printf("\n");
    return 0;
}

评论

matthew99
y[sa[i-1]+k]==y[sa[i]+k] duang的一声爆数组了 这个模板是错的,早就有人指出过
haogram
错误在第18行:**for(i=n-k; i<n; i++) y[p++] = i;** 这样顺序操作会将“qqq”排在“qq”之前,导致基数排序失效。 所以应当倒序操作。即将循环改为**for(i=n-1; i>=n-k; i--) y[p++] = i;** 同时,正如@matthew99(orz)所指出的,sa[i]+k可以达到2n,数组爆了。
Johann
参考罗穗骞的论文可以知道,字符串的每个元素的值为0~m-1,其中原字符串中每个元素的值为1~m-1,并在字符串的末尾添加一个值为0的字符,这样才能保证这种做法的正确性。 在刘汝佳的书中,这个细节没有被提到,是原书中较大的一个纰漏。 建议可以阅读一下巨神的论文,有详细的注解,使用的是非常类似的模板。 另外,不介意的话,也可以看一下本蒟蒻的代码。使用的就是这个模板,可以通过。
Ciki
似乎只要把刘汝佳的代码改成数组从1标号就是对的。。。http://uoj.ac/submission/12867很久以前用pascal写的(虽说爆数组的问题还是有的)
wjyi
http://uoj.ac/submission/81324 这个是完全按照刘汝佳上的代码写的,没有任何修改,过了#35

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。