您的位置:首页 > 其它

[后缀数组+离散化+二分] poj 3261 Milk Patterns

2014-08-29 16:58 316 查看
题意:求至少重复k次的最长可重叠子串

思路:因为数据比较大,所以要先离散化,然后就是后缀数组加二分,因为可重叠就更是裸裸的。

#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
#include"map"
using namespace std;
#define N 200350
int wa
,wb
,wv
,wws
;
int sa
,ra
,height
;
int v
;
int cmp(int *r,int a,int b,int l)
{
    return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(int n,int m)
{
    int i,j,p,*x=wa,*y=wb;
    for(i=0;i<m;i++) wws[i]=0;
    for(i=0;i<n;i++) wws[x[i]=v[i]]++;
    for(i=1;i<m;i++) wws[i]+=wws[i-1];
    for(i=n-1;i>=0;i--) sa[--wws[x[i]]]=i;
    for(j=1,p=1;p<n;j*=2,m=p)
    {
        for(i=n-j,p=0;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<n;i++) wv[i]=x[y[i]];
        for(i=0;i<m;i++) wws[i]=0;
        for(i=0;i<n;i++) wws[wv[i]]++;
        for(i=1;i<m;i++) wws[i]+=wws[i-1];
        for(i=n-1;i>=0;i--) sa[--wws[wv[i]]]=y[i];
        for(swap(x,y),p=1,i=1,x[sa[0]]=0;i<n;i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
    }
    return ;
}
void gethei(int n)
{
    int i,j,k=0;
    for(i=1;i<=n;i++) ra[sa[i]]=i;
    for(i=0;i<n;i++)
    {
        if(k) k--;
        j=sa[ra[i]-1];
        while(v[i+k]==v[j+k])
            k++;
        height[ra[i]]=k;
    }
    return ;
}
int ok(int x,int k,int n)
{
    int sum=1,i;
    for(i=1;i<=n;i++)     //因为可以重叠,所以直接考虑就好了。
    {
        if(height[i]>=x)
        {
            sum++;
            if(sum>=k) return 1;
        }
        else sum=1;
    }
    return 0;
}
int main()
{
    int n,k;
    while(scanf("%d%d",&n,&k)!=-1)
    {
        int m=0,l=2;    //l代表离散完的值,因为最后要是0所以不能从0开始
        map<int,int>mark;  //离散化
        while(n--)
        {
            int x;
            scanf("%d",&x);
            if(!mark[x]) mark[x]=l++;

            v[m++]=mark[x];
        }
        v[m]=0;
        da(m+1,l);
        gethei(m);
        int li=0,ri=m;
        int ans=0;
        while(li<=ri)  //二分枚举长度
        {
            int mid=(li+ri)/2;
            if(ok(mid,k,m))
            {
                ans=mid;
                li=mid+1;
            }
            else ri=mid-1;
        }
        printf("%d\n",ans);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: