poj3261 Milk Patterns

【题意】

求重复k次可重叠子串长度

【分析】

height分组,一组内有k个后缀即可

【代码】

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2e4+5;
const int maxm=1e6+5;
int n,k;
int a[maxn],h[maxn],maxi,id[maxn];
int sa[maxn],rk[maxn],oldrk[maxn],cnt[maxn],fz[maxn];
bool cmp(int x,int y,int w)
{
    return oldrk[x]==oldrk[y] && oldrk[x+w]==oldrk[y+w];
}
void calcsa()
{
    int m=maxi;
    for(int i=0;i<=m;i++) cnt[i]=0;
    for(int i=1;i<=n;i++) cnt[rk[i]=a[i]]++;
    for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
    for(int i=n;i>=1;i--) sa[cnt[rk[i]]--]=i;
    int i,p;
    for(int w=1;;w<<=1,m=p)
    {
        for(p=0,i=n;i>n-w;i--) id[++p]=i;
        for(i=1;i<=n;i++) if(sa[i]>w) id[++p]=sa[i]-w;
        for(i=0;i<=m;i++) cnt[i]=0;
        for(i=1;i<=n;i++) cnt[fz[i]=rk[id[i]]]++;
        for(i=1;i<=m;i++) cnt[i]+=cnt[i-1];
        for(i=n;i>=1;i--) sa[cnt[fz[i]]--]=id[i];
        for(i=1;i<=n;i++) oldrk[i]=rk[i];
        for(p=0,i=1;i<=n;i++) rk[sa[i]]=cmp(sa[i],sa[i-1],w)?p:++p;
        if(p==n)
        {
            for(i=1;i<=n;i++) sa[rk[i]]=i;
            break;
        }
    }
}
void calch()
{
    int i,k=0;
    for(i=1;i<=n;i++)
    {
        if(k) k--;
        while(a[i+k]==a[sa[rk[i]-1]+k]) k++;
        h[rk[i]]=k;
    }
}
bool check(int x)
{
    int cnt=1;
    for(int i=1;i<=n;i++)
    {
        if(h[i]>=x)
            cnt++;
        else
            cnt=1;
        if(cnt>=k) return 1;
    }
    return 0;
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),maxi=max(maxi,a[i]);
    calcsa();
    calch();
    int l=0,r=n,ans;
    while(l<=r)
    {
        int mid=l+r>>1;
        if(check(mid)) ans=mid,l=mid+1;
        else r=mid-1;
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2021-04-27 19:25  andyc_03  阅读(40)  评论(0编辑  收藏  举报