POJ3261 Milk Patterns 题解&代码

来源:互联网 发布:桌面中考倒计时软件 编辑:程序博客网 时间:2024/04/27 17:40

二分后对后缀数组的height分组…解决
第一次写(chao)后缀数组,调了两个多小时,代码都不会抄【笑
本来该附后缀数组学习记录,感觉快要吃饭了不想写…再说吧

(正文在最后)发现了一个很玄妙的地方,二分方法不同的话时间差很大…大概是数据比较玄学?

这是63ms版

    l=1,r=n,mid;    while(l<r)    {        mid=(l+r)/2;        if(check(mid))l=mid+1;        else r=mid;    }    printf("%d\n",r-1);

这是32ms版

    l=1,r=n,mid;    while(l<=r)    {        mid=(l+r)/2;        if(check(mid))l=mid+1;        else r=mid-1;    }    printf("%d\n",r);

代码

#include<iostream>#include<cstdio>#include<algorithm>using namespace std;const int maxn=20005;const int maxm=20005;int n,k,l,r,mid;int num[maxn],sa[maxn],rank[maxn],height[maxn];int wa[maxn],wb[maxn],wv[maxn],cnt[maxm];void DA(int *r,int n,int m){    int *x=wa,*y=wb,p;    for(int i=0;i<m;i++)cnt[i]=0;    for(int i=0;i<n;i++)cnt[x[i]=r[i]]++;    for(int i=1;i<m;i++)cnt[i]+=cnt[i-1];    for(int i=n-1;i>=0;i--)sa[--cnt[x[i]]]=i;    for(int j=1;j<n;j<<=1)    {        p=0;        for(int i=n-j;i<n;i++)y[p++]=i;        for(int i=0;i<n;i++)if(sa[i]-j>=0)y[p++]=sa[i]-j;        for(int i=0;i<n;i++)wv[i]=x[y[i]];        for(int i=0;i<m;i++)cnt[i]=0;        for(int i=0;i<n;i++)cnt[wv[i]]++;        for(int i=1;i<m;i++)cnt[i]+=cnt[i-1];        for(int i=n-1;i>=0;i--)sa[--cnt[wv[i]]]=y[i];        swap(x,y);        p=1;x[sa[0]]=0;        for(int i=1;i<n;i++)            x[sa[i]]=((y[sa[i]]==y[sa[i-1]]) && (y[sa[i]+j]==y[sa[i-1]+j]))?p-1:p++;        if(p>=n)break;        m=p;    }    for(int i=1;i<n;i++)rank[sa[i]]=i;}void calheight(int *r,int n){    int j=0,k=0;    for(int i=0;i<n;height[rank[i]]=k,i++)        for(k?k--:k=0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);}bool check(int len){    int temp=2,tot,cnt;    while(true)    {        while(temp<=n && height[temp]<len)temp++;        if(temp>n) break;        for(cnt=1;temp<=n && height[temp]>=len;cnt++)temp++;        if(cnt>=k)return true;    }    return false;}int main(void){    scanf("%d%d",&n,&k);    for(int i=0;i<n;i++)        scanf("%d",&num[i]);    DA(num,n+1,maxm);    calheight(num,n);    l=1,r=n,mid;    while(l<r)    {        mid=(l+r)/2;        if(check(mid))l=mid+1;        else r=mid;    }    printf("%d\n",r-1);    return 0;}
0 0