POJ 1743 Musical Theme

Description

一个数列求对应差相等最长的一段。(nleqslant 2 imes 10^4)

Solution

后缀数组+二分。

将数列差分一下,一段字符串在(height)数组上一定是连续的一段,二分一个答案,找到一段(>=mid)的区间,然后记录一下最大最小值。

因为(mid)会将他们分成一段段区间,最后判断一下即可。

Code

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

const int N = 20050;

inline int in(int x=0,char ch=getchar()) { while(ch>'9'||ch<'0') ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();return x; }

int n,m;
int a[N],b[N];

namespace SA {
	int t1[N],t2[N],c[N],sa[N],rk[N],ht[N];
	
	void clear() {
		memset(sa,0,sizeof(sa));
		memset(rk,0,sizeof(rk));
		memset(ht,0,sizeof(ht));
	}
	void get_sa(int a[],int n=::n,int m=::m) {
		int *x=t1,*y=t2;
		for(int i=1;i<=m;i++) c[i]=0;
		for(int i=1;i<=n;i++) c[x[i]=a[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,p=0;k<n;k<<=1,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[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]]=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_ht(int a[],int n=::n) {
		for(int i=1;i<=n;i++) rk[sa[i]]=i;
		for(int i=1,j,k=0;i<=n;ht[rk[i++]]=k)
			for(j=sa[rk[i]-1],k=k?k-1:k;a[i+k]==a[j+k];k++);
	}
}

using namespace SA;

int chk(int x) {
	for(int i=1,j;i<=n;i=j) {
		int mi=n,mx=0;
		if(ht[i]<x) { j=i+1;continue; }
		mi=min(mi,sa[i-1]),mx=max(mx,sa[i-1]);
		for(j=i;j<=n && ht[j]>=x;mi=min(mi,sa[j]),mx=max(mx,sa[j]),j++);
		if(mi+x<=mx) return 1;
	}return 0;
}

void Solve() {
	int l=0,r=n;
	for(;l<=r;) {
		int mm=(l+r)>>1;
		if(chk(mm)) l=mm+1;
		else r=mm-1;
	}printf("%d
",r>3?r+1:0);
}

int main() {
	for(;;) {
		if(!(n=in())) break;
		for(int i=1;i<=n;i++) b[i]=in();
		for(int i=1;i<n;i++) a[i]=b[i+1]-b[i]+100;
		n--;
//		n=in();
//		for(int i=1;i<=n;i++) a[i]=in();
//		for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
		clear();
		get_sa(a,n,200);
//		cout<<"qwq"<<endl;
//		for(int i=1;i<=n;i++) cout<<sa[i]<<" ";cout<<endl;
		get_ht(a,n);
//		for(int i=1;i<=n;i++) cout<<ht[i]<<" ";cout<<endl;
		Solve();
	}return 0;
}

  

原文地址:https://www.cnblogs.com/beiyuoi/p/6646324.html