http://www.elijahqi.win/2017/07/14/poj1743/
Musical Theme
Description
A musical melody is represented as a sequence of N (1<=N<=20000)notes that are integers in the range 1..88, each representing a key on the piano. It is unfortunate but true that this representation of melodies ignores the notion of musical timing; but, this programming task is about notes and not timings.
Many composers structure their music around a repeating &qout;theme&qout;, which, being a subsequence of an entire melody, is a sequence of integers in our representation. A subsequence of a melody is a theme if it:
is at least five notes long
appears (potentially transposed – see below) again somewhere else in the piece of music
is disjoint from (i.e., non-overlapping with) at least one of its other appearance(s)
Transposed means that a constant positive or negative value is added to every note value in the theme subsequence.
Given a melody, compute the length (number of notes) of the longest theme.
One second time limit for this problem’s solutions!
Input
The input contains several test cases. The first line of each test case contains the integer N. The following n integers represent the sequence of notes.
The last test case is followed by one zero.
Output
For each test case, the output file should contain a single line with a single integer that represents the length of the longest theme. If there are no themes, output 0.
Sample Input
30 25 27 30 34 39 45 52 60 69 79 69 60 52 45 39 34 30 26 22 18 82 78 74 70 66 67 64 60 65 80 0
Sample Output
5
Hint
Use scanf instead of cin to reduce the read time.
Source
LouTiancheng@POJ
程序框架
1、预处理计算相邻之间的差值,调整为整数得到序列s
2、后缀数组处理s注意末尾加如特殊结束符
3、二分答案
4、height数组分组判断是否符合条件
需要满足最长不重叠的子串
二分答案 验证答案是否正确
如何验证?
需要扫描全部heighti[] 判断height是否>=ans
并且在height>=ans的这些数据中寻找sa[]即判断满足条件的最长和最短的差值是否大于ans 的连续一段区间
#include<cstdio>
#include<cstring>
#define N 22000
inline int read(){
int x=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch<='9'&&ch>='0') {x=x*10+ch-'0';ch=getchar();}
return x;
}
int st[200],count[N],rank[N<<1],rank1[N],s[N],tmp[N],n,k,sa[N],height[N];
inline int max(int x,int y){
return x>y?x:y;
}
inline int min(int x,int y){
return x<y?x:y;
}
inline bool check(int x){
int max1=sa[1],min1=sa[1];
for (int i=2;i<=n;++i){
if (height[i]>=x){
max1=max(max1,sa[i]);
min1=min(min1,sa[i]);
if (max1-min1>=x) return 1;
}else{
max1=min1=sa[i];
}
}
return 0;
}
int main(){
freopen("poj1743.in","r",stdin);
freopen("poj1743.out","w",stdout);
while (1){
n=read();if (n==0) break;
for (int i=1;i<=n;++i) s[i]=read();
for (int i=1;i<n;++i) s[i]=s[i+1]-s[i]+100;
// n--;
s[n]=200;
memset(st,0,sizeof(st));
memset(rank,0,sizeof(rank));
memset(rank1,0,sizeof(rank1));
for (int i=1;i<=n;++i)st[s[i]]=1;
for (int i=1;i<=200;++i) st[i]+=st[i-1];
for (int i=1;i<=n;++i) rank[i]=st[s[i]];
k=0;
for (int p=1;k!=n;p+=p){
memset(count,0,sizeof(count));
for (int i=1;i<=n;++i) count[rank[i+p]]++;
for (int i=1;i<=n;++i) count[i]+=count[i-1];
for (int i=n;i>=1;--i) tmp[count[rank[i+p]]--]=i;
memset(count,0,sizeof(count));
for (int i=1;i<=n;++i) count[rank[i]]++;
for (int i=1;i<=n;++i) count[i]+=count[i-1];
for (int i=n;i>=1;--i) sa[count[rank[tmp[i]]]--]=tmp[i];
memcpy(rank1,rank,sizeof(rank)>>1);
rank[sa[1]]=k=1;
for (int i=2;i<=n;++i){
if (rank1[sa[i]]!=rank1[sa[i-1]]||rank1[sa[i]+p]!=rank1[sa[i-1]+p]) ++k;
rank[sa[i]]=k;
}
}
k=0;
memset(height,0,sizeof(height));
for (int i=1;i<=n;++i){
if (rank[i]==1) {
height[rank[i]]=0;continue;
}
k=k==0?0:k-1;
while (s[i+k]==s[sa[rank[i]-1]+k])++k;
height[rank[i]]=k;
}
//for (int i=1;i<=n;++i) printf("%d ",height[i]);
// for (int i=1;i<=n;++i) printf("%d ",sa[i] );
int ans=-1,l=4,r=n;
while (l<r){
int mid=(l+r)>>1;
if (check(mid)) {
ans=mid;l=mid+1;
}else r=mid;
}
printf("%d\n",ans+1);
}
return 0;
}