POJ1743:Musical Theme

来源:互联网 发布:java课题设计 编辑:程序博客网 时间:2024/05/21 07:00

Poj1743

就先把相邻两个数相减构成一个新的数组再做咯。(再离散化一下)
然后发现题目要求的就是两个后缀的最长不相交前缀。
那么二分+判定就好了。具体看看代码就明白了。

【代码】

#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <queue>#include <cmath>#include <vector>#include <stack>#define N 20005#define INF 0x7fffffffusing namespace std;typedef long long ll;ll read(){    ll x=0,f=1;char ch=getchar();    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}    return x*f;}int tot,n,m,ans;int a[N],c[N],sa[N],height[N],rank[N],x[N],y[N],s[N],hash[N];int Find(int x){    int l=1,r=tot,rtn;    while(l<=r)    {        int mid=l+r>>1;        if(hash[mid]>=x) rtn=mid,r=mid-1;        else l=mid+1;    }    return rtn;}void Input_Init(){    for(int i=1;i<=n;i++) a[i]=read();    for(int i=1;i<n;i++) s[i]=hash[i]=a[i+1]-a[i];    sort(hash+1,hash+n);    tot=unique(hash+1,hash+n)-hash-1;    for(int i=1;i<n;i++) s[i]=Find(s[i]);}void Build_Sa(){    m=tot+1;s[n]=m;    for(int i=1;i<=m;i++) c[i]=0;    for(int i=1;i<=n;i++) c[x[i]=s[i]]++;    for(int i=1;i<=m;i++) c[i]+=c[i-1];    for(int i=n;i;i--) sa[c[x[i]]--]=i;    for(int k=1;k<=n;k<<=1)    {        int p=0;        for(int i=n-k+1;i<=n;i++) y[++p]=i;        for(int i=1;i<=n;i++) if(sa[i]>k) y[++p]=sa[i]-k;        for(int i=1;i<=m;i++) c[i]=0;        for(int i=1;i<=n;i++) c[x[y[i]]]++;        for(int i=1;i<=m;i++) c[i]+=c[i-1];        for(int i=n;i;i--) sa[c[x[y[i]]]--]=y[i];        swap(x,y);x[sa[1]]=1;p=1;        for(int i=2;i<=n;i++)             x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p:++p;        if(p>=n) break;m=p;    }}void Get_Height(){    for(int i=1;i<=n;i++) rank[sa[i]]=i;    int k=0;    for(int i=1;i<=n;i++)    {        if(k) k--;        int j=sa[rank[i]-1];        while(s[i+k]==s[j+k]) k++;        height[rank[i]]=k;    }}bool Judge(int mid){    int mn=INF,mx=-INF;    for(int i=2;i<=n;i++)    {        if(height[i]>=mid) {            mn=min(mn,min(sa[i],sa[i-1]));            mx=max(mx,max(sa[i],sa[i-1]));        }        else {            if(mx-mn>mid) return true;            mn=INF,mx=-INF;         }    }    return false;}void Solve(){    int l=4,r=(n-1)>>1;    while(l<=r)    {        int mid=l+r>>1;        if(Judge(mid)) ans=mid+1,l=mid+1;        else r=mid-1;    }    printf("%d\n",ans);}int main(){    while(1)    {        n=read();ans=0;        if(!n) break;        Input_Init();        Build_Sa();        Get_Height();        Solve();    }    return 0;}
原创粉丝点击