poj1743 Musical Theme

【题意】

找出最长的相似不重叠子串,这里相似定义为两个串每次字符对应的差值相同

【分析】

显然,我们可以首先讲相邻两个的差值作为新的字符串来比较,这样原问题就转换为了求最长的不重叠重复子串

先利用二分,转换为判定性问题,然后对height进行分组,大于等于mid的可以分在一组,如果这一组内的最大和最小的位置差大于等于长度,也就是说这两个串是错开的,那么就可以返回存在

【代码】

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+5;
int n;
int sa[maxn],rk[maxn],h[maxn];
int cnt[maxn],fz[maxn],a[maxn],id[maxn],oldrk[maxn];
bool cmp(int x,int y,int w)
{
    return oldrk[x]==oldrk[y] && oldrk[x+w]==oldrk[y+w];
}
void calcsa()
{
    int m=233,p,i;
    for(i=0;i<=m;i++) cnt[i]=0;
    for(i=1;i<=n;i++) cnt[rk[i]=a[i]]++;
    for(i=1;i<=m;i++) cnt[i]+=cnt[i-1];
    for(i=n;i>=1;i--) sa[cnt[rk[i]]--]=i;
    for(int w=1;;w<<=1,m=p)
    {
        for(p=0,i=1;i<=w;i++) id[++p]=n-i+1;
        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];
        memcpy(oldrk,rk,sizeof(rk));
        rk[sa[1]]=p=1;
        for(i=2;i<=n;i++) rk[sa[i]]=cmp(sa[i],sa[i-1],w)?p:++p;
        if(p==n)
            break;
    }
}
void calch()
{
    int i,k;
    for(i=1,k=0;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 maxx,minn;
    maxx=minn=sa[1];
    for(int i=2;i<=n;i++)
    {
        if(h[i]>=x-1)
        {
            minn=min(minn,sa[i]);
            maxx=max(maxx,sa[i]);
        }
        else minn=maxx=sa[i];
        if(maxx-minn>=x) return 1;
    }
    return 0;
}
int main()
{
    freopen("piano.in","r",stdin);
    freopen("piano.out","w",stdout);
    while(scanf("%d",&n)!=EOF && n)
    {
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=n;i>=1;i--) a[i]-=a[i-1]-100;
        calcsa();
        calch();
        int l=0,r=n,ans;
        while(l<=r)
        {
            int mid=l+r>>1;
            if(check(mid)) l=mid+1,ans=mid;
            else r=mid-1;
        }
        printf("%d\n",ans>=5?ans:0);
    }
    return 0;
}

 

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