poj 1743 Musical Theme(后缀数组、二分)

题目链接:

http://poj.org/problem?id=1743

题目大意:

求不重叠的最长相同变化的子串,也就是最大长度的不重叠重复子串,输出其长度。

思路:

可以利用后缀数组中的height数组。height数组的性质:hegiht[i]表示后缀排名i和i-1的最长公共子序列。现在要求不重叠的重复子串,我们可以将height分组,对于hegiht[i]>=p来说,既然已经满足了lcp>=p,那么剩下的我们只需要满足这两个子串位置>=p,也就是sa[i]-sa[j]>=p。

所以我们只需要二分枚举最大长度p,然后判断在这个长度上能否满足条件即可。

代码:

#include
#include
#include
using namespace std;
const int MAXN = 20005;
int rank[MAXN],height[MAXN];
int str[MAXN],s[MAXN];
int sa[MAXN],t[MAXN],t2[MAXN],c[MAXN];
void build_sa(int m,int n){
    int i, *x=t, *y=t2;
    for(i=0;i=0;i--)sa[--c[x[i]]]=i;
    for(int k=1;k<=n;k<<=1){
        int p=0;
        for(i=n-k;i=k)y[p++]=sa[i]-k;

        for(i=0;i=0;i--)sa[--c[x[y[i]]]]=y[i];

        swap(x,y);
        p=1;x[sa[0]]=0;
        for(i=1;i=n)break;
        m=p;
    }
}
void getHeight(int n){
    int i,j,k=0;
    for(i=0;i<=n;i++){rank[sa[i]]=i;}
    for(i=0;i>1;
            maxi=0;mini=9999999;
            for(i=1;i<=n;i++){
                if(height[i]>mid){
                    mini=min(mini,sa[i]);
                    mini=min(mini,sa[i-1]);
                    maxi=max(maxi,sa[i]);
                    maxi=max(maxi,sa[i-1]);
                }
            }
            if(maxi-mini>=mid)l=mid+1;
            else r=mid-1;
        }
        if(r<4)printf("0\n");
        else
        printf("%d\n",r+1);
    }
}


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