POJ1743-----后缀数组+二分(男人八题之一)

题目地址:http://poj.org/problem?id=1743

题目意思:

给你n个音符,每个音符到另外一个音符,会有一个转换值,即差值,形成一个串。

让你找出里面最长的重复串(至少重复2次),且不相互覆盖

要求,如果组成这些串的音符要>=5,即音乐差值组成的串要大于等于4

否则输出0

解题思路:

先二分答案,把题目变成判定性问题:判断是否
存在两个长度为k 的子串是相同的,且不重叠。解决这个问题的关键还是利用
height 数组。把排序后的后缀分成若干组,其中每组的后缀之间的height 值都
不小于k。例如,字符串为“aabaaaab”,当k=2 时,后缀分成了4 组,如图所示。



POJ1743-----后缀数组+二分(男人八题之一)_第1张图片
容易看出,有希望成为最长公共前缀不小于k 的两个后缀一定在同一组。然
后对于每组后缀,只须判断每个后缀的sa 值的最大值和最小值之差是否不小于
k。如果有一组满足,则说明存在,否则不存在。整个做法的时间复杂度为
O(nlogn)。本题中利用height 值对后缀进行分组的方法很常用,请读者认真体
会。

这是看的罗的论文的思路,但是有一个问题,罗是把r[n-1]作为额外字符的,但是他的模板给的不符

所以如果直接抄他的模板,要根据自己的来,这也是为什么要理解的原因,下面上代码:

#include
#include
#include

using namespace std;

const int maxn = 20000+10;

int str[maxn];

int wa[maxn],wb[maxn],wv[maxn];
int c[maxn];
int cmp(int *r,int a,int b,int l)
{
    return r[a]==r[b] && r[a+l]==r[b+l];
}

void cal_the_houzhui(int *r,int *sa,int n,int m)
{
    int i,j,p;
    int *x=wa,*y=wb;

    //先直接对每个后缀的第一个字符进行基数排序
    for(i=0;i=0;i--)
        sa[--c[x[i]]]=i;

    //然后进行log级的基数排序,使得sa数组稳定
    p=1;
    for(j=1;p=j)
                y[p++]=sa[i]-j;
        for(i=0;i=0;i--)
            sa[--c[wv[i]]] = y[i];
        swap(x,y);
        p=1;
        x[sa[0]] = 0;
        for(i=1;i=mid)
        {
            _min=min(_min,_sa[i]);
            _max=max(_max,_sa[i]);
            if(_max-_min>=mid)
            {
                return true;
            }

        }
        else//如果中间发生断层,那就要另分一组了
            _min=_max=_sa[i];
    }
    return false;
}

void solve()
{
    cal_the_houzhui(str,_sa,n,256);
    cal_the_height(str,_sa,n);
    int low=1,high=n;
    int ans=-1;
    while(low<=high)
    {
        int mid=(low+high)>>1;
        if(judge(mid))
        {
            ans=mid;
            low=mid+1;
        }
        else
            high=mid-1;
    }
    if(ans>=4)//为什么是4,因为这是4个差,就是5个数
        printf("%d\n",ans+1);
    else
        puts("0");
}

int main()
{

    while(~scanf("%d",&n) && n)
    {
        int b,a;
        scanf("%d",&b);
        if(n==1)
        {
            printf("0\n");
            continue;
        }
        for(int i=0;i





你可能感兴趣的:(数据结构,字符串)