后缀数组

具体请看论文....

POJ 1743 Musical Theme

不重叠的最长重复子串

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

using namespace std;

#define N 20100

int p[N];

int sa[N],rank[N],height[N];

int wa[N],wb[N],c[N];

//sa[i] 表示排名为i的下标

//rank[i]表示i的排名

//height[i]表示sa[i]和sa[i-1]的最长前缀

void build_sa(int s[],int n,int m)

{

    int i,j,p,*x = wa,*y = wb;

    //初始化基数排序

    for(i = 0;i < m;i ++)

    c[i] = 0;

    for(i = 0;i < n;i ++)

    c[x[i] = s[i]] ++;

    for(i = 1;i < m;i ++)

    c[i] += c[i-1];

    for(i = n-1;i >= 0;i --)

    sa[--c[x[i]]] = i;



    for(j = 1;j <= n;j <<= 1)

    {

        p = 0;

        //y[i] 表示第二关键字排名为i的下标

        for(i = n-j;i < n;i ++)

        y[p++] = i;

        //如果后缀长度不到j的,第二关键字排名靠前

        for(i = 0;i < n;i ++)

        if(sa[i] >= j) y[p++] = sa[i] - j;

        //sa[i] < j的时候不可能为第二关键字,位置sa[i]-j的第二关键字为sa[i],

        //他的排名为p



        //按第一关键字排序

        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];

        //按y数组的存的下标顺序,基数排序

        for(i = n-1;i >= 0;i --)

        sa[--c[x[y[i]]]] = y[i];



        swap(x,y);

        //生成新的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]+j] == y[sa[i]+j]?p-1:p++;

        if(p >= n) break;

        m = p;

    }



}

void get_height(int s[],int n)

{

    int i,j,k = 0;

    for(i = 1;i <= n;i ++)

    rank[sa[i]] = i;

    //看论文,有证明

    for(i = 0;i < n;i ++)

    {

        if(k) k--;

        j = sa[rank[i]-1];

        while(s[i+k]==s[j+k]) k ++;

        height[rank[i]] = k;

    }

}

int judge(int mid,int n)

{

    int minz,maxz,i;

    minz = maxz = sa[1];

    for(i = 2;i <= n;i ++)

    {

        if(height[i] < mid)

        {

            minz = maxz = sa[i];

        }

        else

        {

            maxz = max(maxz,sa[i]);

            minz = min(minz,sa[i]);

            if(maxz-minz > mid)

            return 1;

        }

    }

    return 0;

}

int main()

{

    int n,i;

    while(scanf("%d",&n)!=EOF)

    {

        if(n == 0) break;

        for(i = 0;i < n;i ++)

        scanf("%d",&p[i]);

        for(i = 0;i < n-1;i ++)

        p[i] = p[i+1] -  p[i] + 90;

        n --;

        p[n] = 0;

        build_sa(p,n+1,200);

        get_height(p,n);

        int str,mid,end;

        str = 1;

        end = n/2;

        while(str < end)

        {

            mid = (str+end + 1)/2;

            if(judge(mid,n))

            str = mid;

            else

            end = mid-1;

        }

        if(end >= 4)

        printf("%d\n",end+1);

        else

        printf("0\n");

    }

    return 0;

}
View Code

 POJ 3261 Milk Patterns

数据非常水,本意是可重叠k次最长子串。

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

using namespace std;

#define N 20100

int p[N];

int sa[N],rank[N],height[N];

int wa[N],wb[N],c[N];

void build_sa(int s[],int n,int m)

{

    int i,j,p,*x = wa,*y = wb;

    for(i = 0;i < m;i ++)

    c[i] = 0;

    for(i = 0;i < n;i ++)

    c[x[i] = s[i]] ++;

    for(i = 1;i < m;i ++)

    c[i] += c[i-1];

    for(i = n-1;i >= 0;i --)

    sa[--c[x[i]]] = i;

    for(j = 1;j <= n;j <<= 1)

    {

        p = 0;

        for(i = n-j;i < n;i ++)

        y[p++] = i;

        for(i = 0;i < n;i ++)

        if(sa[i] >= j) y[p++] = sa[i] - j;

        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]+j] == y[sa[i]+j]?p-1:p++;

        if(p >= n) break;

        m = p;

    }



}

void get_height(int s[],int n)

{

    int i,j,k = 0;

    for(i = 1;i <= n;i ++)

    rank[sa[i]] = i;

    for(i = 0;i < n;i ++)

    {

        if(k) k--;

        j = sa[rank[i]-1];

        while(s[i+k]==s[j+k]) k ++;

        height[rank[i]] = k;

    }

}

int judge(int mid,int n,int k)

{

    int flag,i;

    flag = 1;

    for(i = 2;i <= n;i ++)

    {

        if(height[i] < mid)

        {

            if(flag >= k) return 1;

            flag = 1;

        }

        else

        {

            flag ++;

        }

    }

    if(flag >= k)

    return 1;

    else

    return 0;

}

int main()

{

    int n,i,maxz,k;

    while(scanf("%d%d",&n,&k)!=EOF)

    {

        maxz = 0;

        for(i = 0;i < n;i ++)

        {

            scanf("%d",&p[i]);

            p[i] ++;

            maxz = max(maxz,p[i]);

        }

        p[n] = 0;

        build_sa(p,n+1,maxz+20);

        get_height(p,n);

        int str,mid,end;

        str = 1;

        end = n/2;

        while(str < end)

        {

            mid = (str+end + 1)/2;

            if(judge(mid,n,k))

            str = mid;

            else

            end = mid-1;

        }

        printf("%d\n",end);

    }

    return 0;

}
View Code

 POJ 2774 Long Long Message

注意把C数组开到N....傻了...

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

using namespace std;

#define N 200100

int sa[N],rank[N],height[N];

int c[N],wa[N],wb[N];

char s1[N],s2[N];

int p[N];

void build_sa(int s[],int n,int m)

{

    int i,j,p,*x = wa,*y = wb;

    for(i = 0;i < m;i ++)

    c[i] = 0;

    for(i = 0;i < n;i ++)

    c[x[i] = s[i]] ++;

    for(i = 1;i < m;i ++)

    c[i] += c[i-1];

    for(i = n-1;i >= 0;i --)

    sa[--c[x[i]]] = i;

    for(j = 1;j <= n;j <<= 1)

    {

        p = 0;

        for(i = n-j;i < n;i ++)

        y[p++] = i;

        for(i = 0;i < n;i ++)

        if(sa[i] >= j) y[p++] = sa[i]-j;

        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]+j] == y[sa[i]+j]?p-1:p++;

        if(p >= n) break;

        m = p;

    }

}

void get_height(int s[],int n)

{

    int i,j,k = 0;

    for(i = 1;i <= n;i ++)

    rank[sa[i]] = i;

    for(i = 0;i < n;i ++)

    {

        if(k) k --;

        j = sa[rank[i]-1];

        while(s[i+k] == s[j+k]) k ++;

        height[rank[i]] = k;

    }

}

int main()

{

    int i,len1,len2,j,n;

    scanf("%s%s",s1,s2);

    len1 = strlen(s1);

    j = 0;

    for(i = 0;i < len1;i ++)

    p[j++] = s1[i]-'a'+1;

    p[j++] = 28;

    len2 = strlen(s2);

    for(i = 0;i < len2;i ++)

    p[j++] = s2[i]-'a'+1;

    p[j] = 0;

    n = j;

    build_sa(p,n+1,30);

    get_height(p,n);

    int ans = 0;

    for(i = 1;i <= n;i ++)

    {

        if(sa[i] < len1&&sa[i-1] > len1)

        ans = max(ans,height[i]);

        if(sa[i] > len1&&sa[i-1] < len1)

        ans = max(ans,height[i]);

    }

    printf("%d\n",ans);

    return 0;

}
View Code

 POJ 3294 Life Forms

感觉复杂度挺高的,n=1的时候需要特判。写的代码有些乱....

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

using namespace std;

#define N 200100

int sa[N],height[N],rank[N];

int c[N],wa[N],wb[N];

int p[N];

char str[101][1101];

int flag[N];

int o[101];

int t;

void build_sa(int s[],int n,int m)

{

    int i,j,p,*x = wa,*y = wb;

    for(i = 0; i < m; i ++)

        c[i] = 0;

    for(i = 0; i < n; i ++)

        c[x[i] = s[i]] ++;

    for(i = 1; i < m; i ++)

        c[i] += c[i-1];

    for(i = n-1; i >= 0; i --)

        sa[--c[x[i]]] = i;

    for(j = 1; j <= n; j <<= 1)

    {

        p = 0;

        for(i = n-j; i < n; i ++)

            y[p++] = i;

        for(i = 0; i < n; i ++)

            if(sa[i] >= j) y[p++] = sa[i] - j;

        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]+j] == y[sa[i]+j]?p-1:p++;

        if(p >= n) break;

        m = p;

    }

}

void get_height(int s[],int n)

{

    int i,j,k = 0;

    for(i = 1; i <= n; i ++)

        rank[sa[i]] = i;

    for(i = 0; i < n; i ++)

    {

        if(k) k --;

        j = sa[rank[i]-1];

        while(s[i+k] == s[j+k]) k ++;

        height[rank[i]] = k;

    }

}

int judge(int mid,int n)

{

    int i,j;

    memset(o,0,sizeof(o));

    o[flag[sa[1]]] = 1;

    for(i = 2; i <= n; i ++)

    {

        if(height[i] < mid)

        {

            int temp = 0;

            for(j = 1; j <= t; j ++)

            {

                if(o[j]) temp ++;

                o[j] = 0;

            }

            if(temp > t/2)

                return 1;

            o[flag[sa[i]]] = 1;

        }

        else

        {

            o[flag[sa[i]]] = 1;

        }

    }

    int temp = 0;

    for(j = 1; j <= t; j ++)

    {

        if(o[j]) temp ++;

        o[j] = 0;

    }

    if(temp > t/2)

        return 1;

    return 0;

}

void fun(int key,int end)

{

    int temp = 0,i;

    for(i = 1; i <= t; i ++)

    {

        if(o[i]) temp ++;

        o[i] = 0;

    }

    if(temp > t/2)

    {

        for(i = 0; i < end; i ++)

        {

            printf("%c",p[sa[key]+i]-1+'a');

        }

        printf("\n");

    }

}

int main()

{

    int n,i,j,len,num,temp,f;

    f = 0;

    while(scanf("%d",&n)!=EOF)

    {

        t = n;

        if(f)printf("\n");

        f = 1;

        if(n == 0) break;

        num = 0;

        temp = 30;

        for(i = 0; i < n; i ++)

        {

            scanf("%s",str[i]);

            len = strlen(str[i]);

            for(j = 0; j < len; j ++)

            {

                flag[num] = i+1;

                p[num++] = str[i][j]-'a'+1;

            }

            flag[num] = 0;

            if(i != n-1)

                p[num++] = temp++;

            else

                p[num] = 0;

        }

        if(n == 1)

        {

            printf("%s\n",str[0]);

            continue;

        }

        build_sa(p,num+1,temp+10);

        get_height(p,num);

        int str,end,mid;

        str = 0;

        end = 5000;

        //for(i = 1;i <= num;i ++)

        //printf("%d ",height[i]);

        while(str < end)

        {

            mid = (str + end + 1)/2;

            if(judge(mid,num))

                str = mid;

            else

                end = mid - 1;

        }

        if(end == 0)

        {

            printf("?\n");

            continue;

        }

        int sz[101];

        memset(sz,0,sizeof(sz));

        memset(o,0,sizeof(o));

        o[flag[sa[1]]] = 1;

        for(i = 2; i <= num; i ++)

        {

            if(height[i] < end)

            {

                fun(i-1,end);

                o[flag[sa[i]]] = 1;

            }

            else

            {

                o[flag[sa[i]]] = 1;

            }

        }

        fun(num,end);

    }

    return 0;

}
View Code

 POJ 3974 Palindrome

最长回文串,跑的有些慢...

这份代码 是水过的,我找的是相邻的最大值并且两个后缀必须在前面或后面,但是abcdba会把abba当成回闻....这题如果改成rmq的话,目测会MLE+TLE,放弃治疗了。

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <cmath>

using namespace std;

#define N 2010000

char str[1000001];

int sa[N],height[N],rank[N];

int p[N],c[N],wa[N],wb[N];

void build_sa(int s[],int n,int m)

{

    int i,j,p,*x = wa,*y = wb;

    for(i = 0;i < m;i ++)

    c[i] = 0;

    for(i = 0;i < n;i ++)

    c[x[i] = s[i]] ++;

    for(i = 1;i < m;i ++)

    c[i] += c[i-1];

    for(i = n-1;i >= 0;i --)

    sa[--c[x[i]]] = i;

    for(j = 1;j <= n;j <<= 1)

    {

        p = 0;

        for(i = n-j;i < n;i ++)

        y[p++] = i;

        for(i = 0;i < n;i ++)

        if(sa[i] >= j) y[p++] = sa[i] - j;

        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]+j] == y[sa[i]+j]?p-1:p++;

        if(p >= n) break;

        m = p;

    }

}

void get_height(int s[],int n)

{

    int i,j,k = 0;

    for(i = 1;i <= n;i ++)

    rank[sa[i]] = i;

    for(i = 0;i < n;i ++)

    {

        j = sa[rank[i]-1];

        if(k) k--;

        while(s[i+k] == s[j+k]) k ++;

        height[rank[i]] = k;

    }

}

int main()

{

    int i,len,n,cas = 1;

    while(scanf("%s",str)!=EOF)

    {

        if(strcmp(str,"END") == 0) break;

        n = 0;

        len = strlen(str);

        for(i = 0;i < len;i ++)

        p[n++] = str[i]-'a'+1;

        p[n++] = 28;

        for(i = 0;i < len;i ++)

        p[n++] = str[len-i-1]-'a'+1;

        p[n] = 0;

        build_sa(p,n+1,30);

        get_height(p,n);

        int ans = 0;

        for(i = 1;i <= n;i ++)

        {

            if(sa[i-1] < len||sa[i] > len)

            ans = max(ans,height[i]);

            if(sa[i-1] > len||sa[i] < len)

            ans = max(ans,height[i]);

        }

        printf("Case %d: %d\n",cas++,ans);

    }

    return 0;

}
View Code

 URAL 1297. Palindrome

最长回文串,这是正解。rmq+后缀数组,调试了好一会,费劲啊!!

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <cmath>

using namespace std;

#define N 2010000

int sa[N],height[N],Rank[N];

int c[N],p[N],wa[N],wb[N];

int bin[31];

int minz[22][N];

char str[N];

void build_sa(int s[],int n,int m)

{

    int i,j,p,*x = wa,*y = wb;

    for(i = 0; i < m; i ++)

        c[i] = 0;

    for(i = 0; i < n; i ++)

        c[x[i] = s[i]] ++;

    for(i = 1; i < m; i ++)

        c[i] += c[i-1];

    for(i = n-1; i >= 0; i --)

        sa[--c[x[i]]] = i;

    for(j = 1; j <= n; j <<= 1)

    {

        p = 0;

        for(i = n-j; i < n; i ++)

            y[p++] = i;

        for(i = 0; i < n; i ++)

            if(sa[i] >= j) y[p++] = sa[i]-j;



        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]+j] == y[sa[i]+j]?p-1:p++;

        if(p >= n) break;

        m = p;

    }

}

void get_height(int s[],int n)

{

    int i,j,k = 0;

    for(i = 1; i <= n; i ++)

        Rank[sa[i]] = i;

    for(i = 0; i < n; i ++)

    {

        if(k) k --;

        j = sa[Rank[i]-1];

        while(s[i+k] == s[j+k]) k ++;

        height[Rank[i]] = k;

    }

}

void init(int n)

{

    int i,j;

    for(i = 1; i <= n; i ++)

        minz[0][i] = height[i];

    for(i = 1; bin[i] <= n; i ++)

    {

        for(j = 1; j + bin[i-1] <= n; j ++)

        {

            minz[i][j] = min(minz[i-1][j],minz[i-1][j+bin[i-1]]);

        }

    }

}

int rmq(int s,int t)

{

    int k = log((t-s+1)*1.0)/log(2.0);

    return min(minz[k][s],minz[k][t-bin[k]+1]);

}

int main()

{

    int i,len,n;

    scanf("%s",str);

    n = 0;

    len = strlen(str);

    for(i = 0; i < len; i ++)

        p[n++] = str[i]+1;

    p[n++] = 299;

    for(i = 0; i < len; i ++)

        p[n++] = str[len-i-1]+1;

    p[n] = 0;

    build_sa(p,n+1,300);

    get_height(p,n);

    for(i = 0; i < 21; i ++)

        bin[i] = 1<<i;

    init(n);

    int s,t,temp,pos,ans = 0;

    for(i = 0; i < len; i ++)

    {

        s = Rank[i+1];

        t = Rank[2*len-i];

        if(s > t) swap(s,t);

        s ++;

        temp = rmq(s,t)*2;

        if(ans < temp)

        {

            ans = temp;

            pos = i - temp/2 + 1;

        }

        s = Rank[i];

        t = Rank[2*len-i];

        if(s > t) swap(s,t);

        s ++;

        temp = rmq(s,t)*2 - 1;

        if(ans < temp)

        {

            ans = temp;

            pos = i - temp/2;

        }

    }

    for(i = 0;i < ans;i ++)

    printf("%c",str[pos+i]);

    return 0;

}
View Code

 POJ 3693 Maximum repetition substring

 可能是水过,看论文上的讲解,完全还是不会啊....

枚举那里看懂了,寻找L*i和L*(i+1)往前最长和往后最长,不知道怎么操作的。不会是把字符串倒过来然后再处理一遍吧。。。往后的很简单,就是height最小值,往前就有点扯了,知道后面的长度x,如果前面的长度大于L- x%L那么就会总长度会+1,总长度+2那些个情况应该是不用考虑的,枚举前面的时候已经算了。还有字典序,完全是乱搞,看了一个大神写的是吧L保存下来,然后枚举sa,判断是否可行.....做个题真难啊....

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <cmath>

using namespace std;

#define N 100100

int bin[30];

int sa[N],height[N],rank[N];

int c[N],p[N],wa[N],wb[N];

char str[N];

int minz[22][N];

int que[10001];

void build_sa(int s[],int n,int m)

{

    int i,j,p,*x = wa,*y = wb;

    for(i = 0;i < m;i ++)

    c[i] = 0;

    for(i = 0;i < n;i ++)

    c[x[i] = s[i]] ++;

    for(i = 1;i < m;i ++)

    c[i] += c[i-1];

    for(i = n-1;i >= 0;i --)

    sa[--c[x[i]]] = i;

    for(j = 1;j <= n;j <<= 1)

    {

        p = 0;

        for(i = n-j;i < n;i ++)

        y[p++] = i;

        for(i = 0;i < n;i ++)

        if(sa[i] >= j) y[p++] = sa[i]-j;

        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]+j] == y[sa[i]+j]?p-1:p++;

        if(p >= n) break;

        m = p;

    }

}

void get_height(int s[],int n)

{

    int i,j,k = 0;

    for(i = 1;i <= n;i ++)

    rank[sa[i]] = i;

    for(i = 0;i < n;i ++)

    {

        if(k) k --;

        j = sa[rank[i]-1];

        while(s[i+k] == s[j+k]) k ++;

        height[rank[i]] = k;

    }

}

void init(int n)

{

    int i,j;

    for(i = 1;i <= n;i ++)

    minz[0][i] = height[i];

    for(i = 1;bin[i] <= n;i ++)

    {

        for(j = 1;j +bin[i-1] <= n;j ++)

        {

            minz[i][j] = min(minz[i-1][j],minz[i-1][j+bin[i-1]]);

        }

    }

}

int rmq(int s,int t)

{

    s = rank[s];

    t = rank[t];

    if(s > t) swap(s,t);

    s ++;

    int k = log((t-s+1)*1.0)/log(2.0);

    return min(minz[k][s],minz[k][t-bin[k]+1]);

}

int main()

{

    int cas = 1,len,i,j;

    for(i = 0;i <= 20;i ++)

    bin[i] = 1<<i;

    while(scanf("%s",str)!=EOF)

    {

        if(str[0] == '#') break;

        len = strlen(str);

        for(i = 0;i < len;i ++)

        p[i] = str[i] - 'a'+1;

        p[len] = 0;

        build_sa(p,len+1,30);

        get_height(p,len);

        init(len);

        int ans = 0,num = 0;

        for(i = 1;i <= len;i ++)

        {

            for(j = 0;j < len;j += i)

            {

                if(j+i >= len) continue;

                int temp,lf,res;

                res = 0;

                temp = rmq(j,j+i);

                res = max(res,temp/i+1);

                lf = i - temp%i;

                if(j-lf >= 0)

                {

                    temp = rmq(j-lf,j-lf+i);

                    if(temp >= lf)

                    res = max(res,temp/i+1);

                }

                if(ans < res)

                {

                    ans = res;

                    num = 0;

                    que[num++] = i;

                }

                else if(ans == res)

                {

                    if(que[num-1] == i) continue;

                    que[num++] = i;

                }

            }

        }

        int pos,lt;

        for(i = 1;i <= len;i ++)

        {

            for(j = 0;j < num;j ++)

            {

                int temp = que[j];

                if(rmq(sa[i],sa[i]+temp) >= (ans-1)*temp)

                {

                    pos = sa[i];

                    lt = temp*ans;

                    break;

                }

            }

            if(j != num) break;

        }

        printf("Case %d: ",cas++);

        for(i = 0;i < lt;i ++)

        printf("%c",str[pos+i]);

        printf("\n");

    }

    return 0;

}
View Code

 POJ 3581 Sequence

很棒的一个题,把一个数字串分为三部分,翻转。特别注意第一个数字最大,倒序之后,最小的后缀,一定是最小的数字开头的,因为最后一个数字为最大,不存在下面这种情况。

后面就是分成两段的情况了,选最小并不一定对。

如 5 0 5 0 2 3 倒过来之后 3 2 0 5 0 5

0 5

0 5 0 5

...

这样选最小的并不一定最好, 0 5  和0 5 0 5前面是一样的。0 5后面其实要比较后一部分的字典序。

做法看这个博客:http://www.cnblogs.com/zcwwzdjn/archive/2012/03/10/2389413.html

就是再复制一遍,注意保证分成两部分sa[i]>=1,这题不用中间隔开字符,要理解思想啊....

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <cmath>

using namespace std;

#define N 201000

int sa[N],height[N],rank[N];

int c[N],wa[N],wb[N];

int p[N],que[N];

int ans[4];

struct node

{

    int x,id;

} num[N];

bool cmp(node a,node b)

{

    return a.x < b.x;

}

void build_sa(int s[],int n,int m)

{

    int i,j,p,*x = wa,*y = wb;

    for(i = 0; i < m; i ++)

        c[i] = 0;

    for(i = 0; i < n; i ++)

        c[x[i] = s[i]] ++;

    for(i = 1; i < m; i ++)

        c[i] += c[i-1];

    for(i = n-1; i >= 0; i --)

        sa[--c[x[i]]] = i;

    for(j = 1; j <= n; j <<= 1)

    {

        p = 0;

        for(i = n-j; i < n; i ++)

            y[p++] = i;

        for(i = 0; i < n; i ++)

            if(sa[i] >= j) y[p++] = sa[i] - j;

        for(i = 0; i < m; i ++)

            c[i] = 0;

        for(i = 0; i < n; i ++)

            c[x[y[i]]] = 0;

        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]+j] == y[sa[i]+j]?p-1:p++;

        if(p >= n) break;

        m = p;

    }

}

int main()

{

    int n,i,temp,tn;

    scanf("%d",&n);

    tn = n;

    for(i = 0; i < n; i ++)

    {

        scanf("%d",&num[i].x);

        que[n-i-1] = num[i].x;

        num[i].id = n-i-1;

    }

    sort(num,num+n,cmp);

    temp = 2;

    p[num[0].id] = 1;

    for(i = 1; i < n; i ++)

    {

        p[num[i].id] = num[i-1].x == num[i].x?temp-1:temp++;

    }

    p[n] = 0;

    build_sa(p,n+1,temp+10);

    ans[0] = 1000000;

    for(i = 1; i <= n; i ++)

    {

        if(sa[i] >= 2)

        {

            ans[1] = sa[i];

            break;

        }

    }

    n = ans[1];

    for(i = 0; i < ans[1]; i ++)

        p[n++] = p[i];

    p[n] = 0;

    build_sa(p,n+1,temp+10);

    for(i = 1; i <= n; i ++)

    {

        if(sa[i] < ans[1]&&sa[i] >= 1)

        {

            ans[2] = sa[i];

            break;

        }

    }

    for(i = ans[1]; i < tn; i ++)

        printf("%d\n",que[i]);

    for(i = ans[2]; i < ans[1]; i ++)

        printf("%d\n",que[i]);

    for(i = 0; i < ans[2]; i ++)

        printf("%d\n",que[i]);

    return 0;

}
View Code

 HDU 4416 Good Article Good sentence

RE了很多次....注意n = 0,数组开小,最后结果LL。

A出现过,B[]没出现的字串。

论文里有求子串的个数,这题麻烦一点,后缀排序后对于sa[i] 要减去前面出现过的和后面出现过的。前面出现过的值肯定是height[i],无论sa[i-1]是A里面的,还是B[]里面的,height[i]是最大值,保证A#B...保证这个#是字典序是次小的,保证了A的相对顺序不变, 再从j+1寻找第一个B[]的后缀,那么rmq(i+1,pos)就是sa[i]后面出现过的,取 max就好,那个rmq从后往前倒着标记一遍就可以求出来。

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <cmath>

using namespace std;

#define N 501000

#define LL __int64

int sa[N],height[N],rank[N];

int c[N],wa[N],wb[N];

int p[N];

int res[N];

char str[N];

void build_sa(int s[],int n,int m)

{

    int i,j,p,*x = wa,*y = wb;

    for(i = 0;i < m;i ++)

    c[i] = 0;

    for(i = 0;i < n;i ++)

    c[x[i] = s[i]] ++;

    for(i = 1;i < m;i ++)

    c[i] += c[i-1];

    for(i = n-1;i >= 0;i --)

    sa[--c[x[i]]] = i;

    for(j = 1;j <= n;j <<= 1)

    {

        p = 0;

        for(i = n-j;i < n;i ++)

        y[p++] = i;

        for(i = 0;i < n;i ++)

        if(sa[i] >= j) y[p++] = sa[i] - j;

        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]+j] == y[sa[i]+j]?p-1:p++;

        if(p >= n) break;

        m = p;

    }



}

void get_height(int s[],int n)

{

    int i,j,k = 0;

    for(i = 1;i <= n;i ++)

    rank[sa[i]] = i;

    for(i = 0;i < n;i ++)

    {

        if(k) k--;

        j = sa[rank[i]-1];

        while(s[i+k]==s[j+k]) k ++;

        height[rank[i]] = k;

    }

}

int main()

{

    int t,cas = 1,i,temp,len,tlen,num;

    int n,j;

    scanf("%d",&t);

    while(t--)

    {

        scanf("%d",&n);

        num = 0;

        for(i = 0;i <= n;i ++)

        {

            scanf("%s",str);

            if(i == 0)

            len = strlen(str);

            tlen = strlen(str);

            for(j = 0;j < tlen;j ++)

            {

                p[num++] = str[j]-'a'+2+n;

            }

            if(i == n)

            p[num] = 0;

            else

            p[num++] = i+1;

        }

        build_sa(p,num+1,n+30);

        get_height(p,num);

        LL ans = 0;

        temp = 0;

        for(i = num;i >= 1;i --)

        {

            if(sa[i] < len)

            {

                res[i] = temp;

                temp = min(height[i],res[i]);

            }

            else

            temp = height[i];

        }

        for(i = 1;i <= num;i ++)

        {

            if(sa[i] < len)

            {

                ans += len - sa[i] - max(height[i],res[i]);

            }

        }

        printf("Case %d: %I64d\n",cas++,ans);

    }

    return 0;

}
View Code

 HDU 3518 Boring counting

水题....

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <cmath>

using namespace std;

#define N 1100

#define LL __int64

int sa[N],height[N],rank[N];

int c[N],wa[N],wb[N];

int p[N];

char str[N];

void build_sa(int s[],int n,int m)

{

    int i,j,p,*x = wa,*y = wb;

    for(i = 0;i < m;i ++)

    c[i] = 0;

    for(i = 0;i < n;i ++)

    c[x[i] = s[i]] ++;

    for(i = 1;i < m;i ++)

    c[i] += c[i-1];

    for(i = n-1;i >= 0;i --)

    sa[--c[x[i]]] = i;

    for(j = 1;j <= n;j <<= 1)

    {

        p = 0;

        for(i = n-j;i < n;i ++)

        y[p++] = i;

        for(i = 0;i < n;i ++)

        if(sa[i] >= j) y[p++] = sa[i] - j;

        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]+j] == y[sa[i]+j]?p-1:p++;

        if(p >= n) break;

        m = p;

    }

}

void get_height(int s[],int n)

{

    int i,j,k = 0;

    for(i = 1;i <= n;i ++)

    rank[sa[i]] = i;

    for(i = 0;i < n;i ++)

    {

        if(k) k --;

        j = sa[rank[i]-1];

        while(s[i+k] == s[j+k]) k ++;

        height[rank[i]] = k;

    }

}

int main()

{

    int i,j,len,maxz,minz;

    while(scanf("%s",str)!=EOF)

    {

        if(str[0] == '#') break;

        len = strlen(str);

        for(i = 0;i < len;i ++)

        p[i] = str[i] - 'a' + 1;

        p[len] = 0;

        build_sa(p,len+1,30);

        get_height(p,len);

        int ans = 0;

        for(i = 1;i <= len;i ++)

        {

            maxz = sa[1];

            minz = sa[1];

            for(j = 2;j <= len;j ++)

            {

                if(height[j] < i)

                {

                    if(minz+i <= maxz) ans ++;

                    maxz = sa[j];

                    minz = sa[j];

                }

                else

                {

                    maxz = max(maxz,sa[j]);

                    minz = min(minz,sa[j]);

                }

            }

            if(minz+i <= maxz) ans ++;

        }

        printf("%d\n",ans);

    }

    return 0;

}
View Code

 HDU 4080 Stammering Aliens

注意n = 1的特殊情况。

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <cmath>

using namespace std;

#define N  100000

int sa[N],height[N],rank[N];

int c[N],wa[N],wb[N];

int p[N];

char str[N];

int m;

void build_sa(int s[],int n,int m)

{

    int i,j,p,*x = wa,*y = wb;

    for(i = 0; i < m; i ++)

        c[i] = 0;

    for(i = 0; i < n; i ++)

        c[x[i] = s[i]] ++;

    for(i = 1; i < m; i ++)

        c[i] += c[i-1];

    for(i = n-1; i >= 0; i --)

        sa[--c[x[i]]] = i;

    for(j = 1; j <= n; j <<= 1)

    {

        p = 0;

        for(i = n-j; i < n; i ++)

            y[p++] = i;

        for(i = 0; i < n; i ++)

            if(sa[i] >= j) y[p++] = sa[i] - j;

        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]+j] == y[sa[i]+j]?p-1:p++;

        if(p >= n) break;

        m = p;

    }

}

void get_height(int s[],int n)

{

    int i,j,k = 0;

    for(i = 1; i <= n; i ++)

        rank[sa[i]] = i;

    for(i = 0; i < n; i ++)

    {

        if(k) k --;

        j = sa[rank[i]-1];

        while(s[i+k] == s[j+k]) k ++;

        height[rank[i]] = k;

    }

}

int judge(int mid,int n)

{

    int i,flag = 1;

    for(i = 1; i <= n; i ++)

    {

        if(height[i] < mid)

        {

            if(flag >= m) return 1;

            flag = 1;

        }

        else

            flag ++;

    }

    if(flag >= m)

        return 1;

    else

        return 0;

}

int main()

{

    int i,len;

    while(scanf("%d",&m)!=EOF)

    {

        if(m == 0) break;

        scanf("%s",str);

        len = strlen(str);

        if(m == 1)

        {

            printf("%d %d\n",len,0);//特判

            continue;

        }

        for(i = 0; i < len; i ++)

        {

            p[i] = str[i] - 'a' + 1;

        }

        p[len] = 0;

        build_sa(p,len+1,30);

        get_height(p,len);

        int str,end,mid;

        str = 0;

        end = len;

        while(str < end)

        {

            mid = (str + end + 1)/2;

            if(judge(mid,len))

                str = mid;

            else

                end = mid - 1;

        }

        if(end == 0)

        {

            printf("none\n");

            continue;

        }

        printf("%d ",end);

        int flag = 1,temp = sa[1],ans;

        ans = 0;

        for(i = 1; i <= len; i ++)

        {

            if(height[i] < end)

            {

                if(flag >= m)

                ans = max(ans,temp);

                temp = sa[i];

                flag = 1;

            }

            else

            {

                temp = max(temp,sa[i]);

                flag ++;

            }

        }

        if(flag >= m)

        ans = max(ans,temp);

        printf("%d\n",ans);

    }

    return 0;

}
View Code

 HDU 4691 Front compression

想了好一会,发现 不会啊。。。。原来看错题了。。。这个比较只是相邻的....挺水的....

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <cmath>

using namespace std;

#define N 300000

#define LL __int64

int sa[N],height[N],rank[N];

int c[N],wa[N],wb[N];

int p[N],sum[N];

int minz[22][N];

int bin[22];

char str[N];

void build_sa(int s[],int n,int m)

{

    int i,j,p,*x = wa,*y = wb;

    for(i = 0;i < m;i ++)

    c[i] = 0;

    for(i = 0;i < n;i ++)

    c[x[i] = s[i]] ++;

    for(i = 1;i < m;i ++)

    c[i] += c[i-1];

    for(i = n-1;i >= 0;i --)

    sa[--c[x[i]]] = i;

    for(j = 1;j <= n;j <<= 1)

    {

        p = 0;

        for(i = n-j;i < n;i ++)

        y[p++] = i;

        for(i = 0;i < n;i ++)

        if(sa[i] >= j) y[p++] = sa[i] - j;

        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]+j] == y[sa[i]+j]?p-1:p++;

        if(p >= n) break;

        m = p;



    }

}

void get_height(int s[],int n)

{

    int i,j,k = 0;

    for(i = 1;i <= n;i ++)

    rank[sa[i]] = i;

    for(i = 0;i < n;i ++)

    {

        if(k) k --;

        j = sa[rank[i]-1];

        while(s[i+k] == s[j+k]) k ++;

        height[rank[i]] = k;

    }

}

void init(int n)

{

    int i,j;

    for(i = 1;i <= n;i ++)

    minz[0][i] = height[i];

    for(i = 1;i <= bin[i];i ++)

    {

        for(j = 1;j + bin[i-1] <= n;j ++)

        {

            minz[i][j] = min(minz[i-1][j],minz[i-1][j+bin[i-1]]);

        }

    }

}

int rmq(int s,int t)

{

    s = rank[s];t = rank[t];

    if(s > t) swap(s,t);

    s ++;

    int k = log((t-s+1)*1.0)/log(2.0);

    return min(minz[k][s],minz[k][t-bin[k]+1]);

}

int fun(int num)

{

    int ans = 0;

    if(num == 0) return 1;

    while(num)

    {

        num /= 10;

        ans ++;

    }

    return ans;

}

int main()

{

    int i,len,n,l,r,pl,pr;

    for(i = 0;i <= 20;i ++)

    bin[i] = 1<<i;

    while(scanf("%s",str)!=EOF)

    {

        len = strlen(str);

        for(i = 0;i < len;i ++)

        {

            p[i] = str[i] - 'a' + 1;

        }

        p[len] = 0;

        build_sa(p,len+1,30);

        get_height(p,len);

        init(len);

        scanf("%d",&n);

        LL ans1,ans2;

        int num,temp;

        ans1 = ans2 = 0;

        pl = pr = 0;

        for(i = 0;i < n;i ++)

        {

            scanf("%d%d",&l,&r);

            ans1 += r - l + 1;

            if(pl == l)

            temp = len - l;

            else

            temp = rmq(pl,l);

            num = min(pr-pl,min(temp,r-l));

            ans2 += fun(num) + 2 + r - l - num;

            pl = l;

            pr = r;

        }

        printf("%I64d %I64d\n",ans1,ans2);

    }

    return 0;

}
View Code

 

你可能感兴趣的:(后缀数组)