POJ 1743 Musical Theme[后缀数组]
来源:互联网 发布:苹果电脑设计软件下载 编辑:程序博客网 时间:2024/06/11 22:31
题目链接:http://poj.org/problem?id=1743
题目大意
给定一段音乐乐谱,其中的音符用数字表示出来( 范围 [ 1,88 ]),要求的是这段乐谱的主旋律。所谓的主旋律,就是满足以下三点要求的一段子串:
1、音符的数目至少为5;
2、重复出现在乐谱中的另一个地方;
3、不相互叠加;
先二分答案,把题目变成判定性问题:判断是否存在两个长度为k 的子串是相同的,且不重叠。
解决这个问题的关键是利用height 数组,把排序后的后缀分成若干组,
其中每组的后缀之间的height值都不小于k。
容易看出,有希望成为最长公共前缀不小于k 的两个后缀一定在同一组。
然后对于每组后缀,只须判断每个后缀的sa 值的最大值和最小值之差是否不小于k。
如果有一组满足,则说明存在,否则不存在。时间复杂度为O(nlogn)。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include<cmath>
#include <algorithm>
const int N=200010;
int min(int a,int b){
returna<b?a:b;
}
int max(int a,int b){
returna>b?a:b;
}
int wa[N],wb[N],wv[N],Ws[N];
int cmp(int *r,int a,int b,int l)
{returnr[a]==r[b]&&r[a+l]==r[b+l];}
void da(const int *r,int *sa,int n,int m){
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) Ws[i]=0;
for(i=0;i<n;i++)Ws[x[i]=r[i]]++;
for(i=1;i<m;i++)Ws[i]+=Ws[i-1];
for(i=n-1;i>=0;i--)sa[--Ws[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p){
for(p=0,i=n-j;i<n;i++)y[p++]=i;
for(i=0;i<n;i++)if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=0;i<n;i++)wv[i]=x[y[i]];
for(i=0;i<m;i++)Ws[i]=0;
for(i=0;i<n;i++)Ws[wv[i]]++;
for(i=1;i<m;i++)Ws[i]+=Ws[i-1];
for(i=n-1;i>=0;i--)sa[--Ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
int sa[N],Rank[N],height[N]; //求height数组
void calheight(const int *r,int *sa,int n){
int i,j,k=0;
for(i=1;i<=n;i++)Rank[sa[i]]=i;
for(i=0;i<n;height[Rank[i++]]=k)
for(k?k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++);
return;
}
int n,num[N],a[N];
bool check(int mid){
intmmax=0,mmin=n;
for(inti=0;i<=n;i++){
if(height[i]<mid){
mmax=sa[i];
mmin=sa[i];
}
else{
mmax=max(mmax,max(sa[i],sa[i-1]));
mmin=min(mmin,min(sa[i],sa[i-1]));
if(mmax-mmin>mid){
return true;
}
}
}
returnfalse;
}
int main()
{
//freopen("C:\\Users\\acm\\Desktop\\001.in","r",stdin);
int i;
while(scanf("%d",&n)&&n){
for(i=0;i<n;i++){
scanf("%d",&a[i]);
}
n--;
for(i=0;i<n;i++){
num[i]=a[i+1]-a[i]+100;
}
num[n]=0;
da(num,sa,n+1,200);
calheight(num,sa,n);
#include <cstdio>
#include <cstring>
#include<cmath>
#include <algorithm>
const int N=200010;
int min(int a,int b){
}
int max(int a,int b){
}
int wa[N],wb[N],wv[N],Ws[N];
int cmp(int *r,int a,int b,int l)
{returnr[a]==r[b]&&r[a+l]==r[b+l];}
void da(const int *r,int *sa,int n,int m){
}
int sa[N],Rank[N],height[N];
void calheight(const int *r,int *sa,int n){
}
int n,num[N],a[N];
bool check(int mid){
}
int main()
{