POJ - 1743 (Musical Theme)

题意:给定一段由整数组成的音乐旋律的序列,每两个整数的差值就是旋律的变化,求找到原序列中最长的两个不覆盖的子串,使得两个子串的旋律变化一致(长度至少为5)

 

分析:把原序列相邻两两整数之间的差值构成一个新数组求出后缀数组,然后二分枚举子串的长度即可;

 

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 4E4+10;

int s[N],m;
int n,sa[N],rk[N],oldrk[N<<1],id[N],px[N],cnt[N],ht[N];

bool cmp(int x,int y,int w){
	return oldrk[x]==oldrk[y] && oldrk[x+w]==oldrk[y+w];
} 

void da(int s[],int n,int m){
	int i,p=0,w,k;
	for(i=1;i<=n;i++) ++cnt[rk[i] = s[i]];
	for(i=1;i<=m;i++) cnt[i] += cnt[i-1];
	for(i=n;i>=1;i--) sa[cnt[rk[i]]--] = i;
	
	for(w=1;w<n;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;
		memset(cnt,0,sizeof(cnt));
		for(i=1;i<=n;i++) ++cnt[px[i] = rk[id[i]]]; 
	    for(i=1;i<=m;i++) cnt[i] += cnt[i-1];
	    for(i=n;i>=1;i--) sa[cnt[px[i]]--] = id[i];
	    memcpy(oldrk,rk,sizeof(rk));
	    
	    for(p=0,i=1;i<=n;i++)
	        rk[sa[i]]=cmp(sa[i],sa[i-1],w)?p:++p;
	}
	
	for(i=1,k=0;i<=n;i++){
		if(k) --k;
		while(s[i+k]==s[sa[rk[i]-1]+k]) ++k;
		ht[rk[i]]=k;
	}
} 

bool check(int len){
	int L,R;
	L=R=-1;
	for(int i=2;i<=n;i++){
		if(ht[i]>=len){
			if(L==-1){
				L=min(sa[i-1],sa[i]);
				R=max(sa[i-1],sa[i]);
			} 
			else{
				L=min(L,min(sa[i-1],sa[i]));
				R=max(R,max(sa[i-1],sa[i]));
			}
		}
		else{
			if(L+len<=R) return 1; 
			L=R=-1;
		}
	}
	return L+len<=R;
}

int main()
{
	while(~scanf("%d",&n)&&n){
		memset(cnt,0,sizeof(cnt));
		int pre; scanf("%d",&pre);
		for(int i=1,x;i<=n-1;i++){
			scanf("%d",&x);
			s[i]=x-pre+100;
			pre=x;
		}
		n--;
        da(s,n,200);
        int l=4,r=n/2,ANS=-1;
        while(l<=r){
        	int m=(l+r)>>1;
        	if(check(m)){
        		ANS=m,l=m+1;
			}
			else r=m-1;
		}
		printf("%d\n",ANS+1);
	} 
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值