POJ 1743 Musical Theme

时间:2023-03-08 23:07:19
POJ 1743 Musical Theme

  感觉最近好混乱......各种OJ都刷一点,感觉不太好......尤其是这种英文题

  这道题一开始还没有看懂。听了ljh大犇的解释后终于明白了。下面我为英语和我一样的人翻译一下题面:

  输入n个数。求最长的两端不交叉的序列,使它们的变化量相同,即相邻两位的差相同。当这个长度小于5时输出0。

  好了,这道题是不是和最长不重叠子串有点像?把原数组差分后,简直一模一样。我们先构出原数组的后缀数组,然后二分一个答案(答案显然具有单调性是吧?),扫一遍height数组看一看是否存在后缀i,j,使得lcp(i,j)>=x && abs(len(j)-len(i))>x 。找到了当前答案(x)就是可行的。一路判断下去就可以辣!不过这道题要注意:原数组差分之后只有n-1个!

  下面贴代码:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout);
#define maxn 200010 using namespace std;
typedef long long llg; int n,ht[maxn],rk[maxn],sa[maxn],c[maxn],a[maxn]; int getint(){
int w=;bool q=;
char c=getchar();
while((c>''||c<'')&&c!='-') c=getchar();
if(c=='-') q=,c=getchar();
while(c>=''&&c<='') w=w*+c-'',c=getchar();
return q?-w:w;
} void build_sa(int m){
int i,*x=rk,*y=ht;
for(i=;i<=m;i++) c[i]=;
for(i=;i<=n;i++) c[x[i]=a[i]]++;
for(i=;i<=m;i++) c[i]+=c[i-];
for(i=n;i;i--) sa[c[x[i]]--]=i;
for(int k=,p;k<=n;k<<=){
p=;
for(i=n-k+;i<=n;i++) y[++p]=i;
for(i=;i<=n;i++) if(sa[i]>k) y[++p]=sa[i]-k;
for(i=;i<=m;i++) c[i]=;
for(i=;i<=n;i++) c[x[y[i]]]++;
for(i=;i<=m;i++) c[i]+=c[i-];
for(i=n;i;i--) sa[c[x[y[i]]]--]=y[i];
swap(x,y); x[sa[]]=; p=;
for(i=;i<=n;i++)
x[sa[i]]=(y[sa[i-]]==y[sa[i]] && y[sa[i-]+k]==y[sa[i]+k])?p:++p;
if(p==n) break; m=p;
}
for(i=;i<=n;i++) rk[sa[i]]=i;
for(int i=,j,k=;i<=n;i++){
if(k) k--;
j=sa[rk[i]-];
while(a[i+k]==a[j+k]) k++;
ht[rk[i]]=k;
}
} bool pd(int x){
for(int i=,ma,mi;i<=n;){
while(ht[i]<x && i<=n) i++;
ma=mi=sa[i-];
while(ht[i]>=x && i<=n){
ma=max(ma,sa[i]);
mi=min(mi,sa[i]);
i++;
}
if(ma-mi>x) return ;
}
return ;
} int main(){
File("a");
n=getint();
while(n){
for(int i=;i<n;i++) a[i]=getint();
for(int i=n-;i;i--) a[i]=a[i]-a[i-]+;
build_sa();
int l=,r=n+,mid;
while(l!=r){
mid=l+r>>;
if(pd(mid)) l=mid+;
else r=mid;
}
if(l<=) printf("0\n");
else printf("%d\n",l);
n=getint();
}
return ;
}