POJ 1743 Musical Theme

Description

A musical melodyis represented as a sequence of N (1<=N<=20000)notes that are integers inthe range 1..88, each representing a key on the piano. It is unfortunate buttrue 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 asequence of integers in our representation. A subsequence of a melody is atheme 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 everynote 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 containsseveral 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 testcase, the output file should contain a single line with a single integer thatrepresents 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 4539 34 30 26 22 18

82 78 74 70 66 67 64 60 65 80

0

Sample Output

5

题目大意:给n个数。数字都在1~88之间。现在求出最长的两段数字,满足一段数字每个数同时加(减)一个数可以得到另一段数字。这样的数字串最短为5.

方法:对于n<10可以直接输出。而对于加(减)一个数得到另一段数字,可以想到,两段数字串分别对相邻位做差得到的数字串恰好相等。即 2 4 9 7 8 10 13可以看出2 4 6相邻位做差为2 3,8 10 12相邻位做差也是2 3.这样就可以做差之后求出最大height值,并保证没有重叠,答案即是最大height+1.再求height值是,我们可以通过二分height,判断是否存在满足条件的height

 

#include <iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<string>
#define MAX 20010
using namespace std;

int wa[MAX] ,wb[MAX] ,wv[MAX] ,ws1[MAX] ,sa[MAX];
int rank1[MAX],height[MAX] ,num[MAX];

int cmp(int *r,int a,int b,int l)
{
    return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(int *r,int *sa ,int n,int m)
{
	int i,j,p,*x=wa,*y=wb,*t;
	for(i=0;i<m;i++) ws1[i]=0;
	for(i=0;i<n;i++) ws1[x[i]=r[i]]++;
	for(i=1;i<m;i++) ws1[i]+=ws1[i-1];
	for(i=n-1;i>=0;i--) sa[--ws1[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++) ws1[i]=0;
		for(i=0;i<n;i++) ws1[wv[i]]++;
		for(i=1;i<m;i++) ws1[i]+=ws1[i-1];
		for(i=n-1;i>=0;i--) sa[--ws1[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;
}
void calheight(int *r,int *sa ,int n)
{
	int i,j,k=0;
	for(i=1;i<=n;i++) rank1[sa[i]]=i;
	for(i=0;i<n;height[rank1[i++]]=k)
		for(k?k--:0,j=sa[rank1[i]-1];r[i+k]==r[j+k];k++);
	return;
}
int main()
{
    int len ,len1 ,max1 ,n;
    while(scanf("%d",&n),n)
    {
        scanf("%d",&num[0]);
        for(int i = 1;i < n;i++)
        {
            scanf("%d",&num[i]);
            num[i-1] = num[i] - num[i-1] + 88;
        }
        if(n<10)
        {
            printf("0\n");
            continue;
        }
		num[n-1] = 0;
        da(num,sa,n,177);
        calheight(num,sa,n-1);
        int flag ,left = 4 ,right = n ,sum = 0 ,min1 ,max1;
        while(left<=right)
        {
            int mid = (left + right) / 2;
            flag = 0;
            for(int i = 0;i<n-1;i++)
            {
                if(height[i]>=mid)
                {
                    min1 = min(sa[i-1],sa[i]);
                    max1 = max(sa[i-1],sa[i]);
                    if(max1 - min1 > mid)
                    {
                        flag = 1;
                        break;
                    }
                    while(height[i]>=mid)
                    {
                        min1 = min(min1,sa[i]);
                        max1 = max(max1,sa[i]);
                        i++;
                        if(max1 - min1 > mid)
                        {
                            flag = 1;
                            break;
                        }
                    }
                }
            }
            if(!flag)
            {
                right = mid - 1;
            }
            else
            {
                sum = mid;
                left = mid + 1;
            }
        }
        if(!sum)
        {
            printf("%d\n",sum);
        }
        else
        {
            printf("%d\n",sum+1);
        }

    }
    return 0;
}


 

你可能感兴趣的:(POJ 1743 Musical Theme)