后缀数组

具体请看论文....

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
",end+1);
        else
        printf("0
");
    }
    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
",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
",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("
");
    }
}
int main()
{
    int n,i,j,len,num,temp,f;
    f = 0;
    while(scanf("%d",&n)!=EOF)
    {
        t = n;
        if(f)printf("
");
        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
",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("?
");
            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
",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("
");
    }
    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
",que[i]);
    for(i = ans[2]; i < ans[1]; i ++)
        printf("%d
",que[i]);
    for(i = 0; i < ans[2]; i ++)
        printf("%d
",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
",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
",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
",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
");
            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
",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
",ans1,ans2);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/naix-x/p/3926564.html