您的位置:首页 > 其它

POJ 1743 Musical Theme

2015-10-10 20:58 337 查看
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.

题意:给出一段只有音高(整数表示),没有节奏的乐谱,问其中最长的曲调相同的没有重叠的两段的长度是多少,如果两个曲调段差值都相同那么也算相同。

思路:

我们要注意到说两段曲调即使每一项的差值相同也算相同,那么,我们可以想到,对应的答案做差并平移(后一项减前一项取差)之后,两段的值应该是对应相等的,那么问题就转化为了求一个字符串的不可重叠最长重复子串。

那么我们怎么去求不可重叠最长重复子串呢,首先对于重复子串首先我们应该能想到height数组,而且要求不重叠,那么也就是存在一段区间,使得 RMQ(height[i], height[j]) >= 4 并且 j - i > len, 由于height独特的性质,对于整个长区间我们可以采用二分的形式去把height数组分组,

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <algorithm>
#include <string.h>

using namespace std;
#define MAXN 20010
int s[MAXN];
int n, sa[MAXN], height[MAXN], _rank[MAXN], tmp[MAXN], top[MAXN];

void makesa()
{
int i, j, len, na;
na = (n < 256 ? 256 : n);
memset(top, 0, na*sizeof(int));
for(i = 0; i < n; i++) top[_rank[i] = s[i] & 0xff] ++;
for( i = 1; i < na; i++) top[i] += top[i - 1];
for( int i = 0; i < n; i++) sa[ --top[_rank[i]]] = i;
for( len = 1; len < n; len <<= 1)
{
for( i = 0; i < n; i++)
{
j = sa[i] - len;
if(j < 0) j += n;
tmp[ top[ _rank[j] ] ++] = j;
}
sa[ tmp[top[0] = 0] ] = j = 0;
for( i = 1; i < n; i++)
{
if(_rank[tmp[i]] != _rank[tmp[i-1]] || _rank[tmp[i] + len] != _rank[tmp[i - 1] + len])
top[++j] = i;
sa[ tmp[i] ] = j;
}
memcpy(_rank, sa, n*sizeof(int));
memcpy(sa, tmp, n*sizeof(int));
if(j >= n - 1) break;
}
}

void lcp( )
{
int i, j, k;
for( j = _rank[height[i = k = 0] = 0]; i < n - 1; i++, k++)
while(k >= 0 && s[i] != s[ sa[j - 1] + k])
height[j] = (k--), j = _rank[sa[j] + 1];
}

bool isok(int len)
{
int l = sa[0], r = sa[0];
for( int i = 1; i <= n; i++)
{
if(height[i] < len)
{
l = sa[i];
r = sa[i];
continue;
}
if(sa[i] < l)
l = sa[i];
if(sa[i] > r)
r = sa[i];
if(r - l > len)
return true;
}
return false;
}

int binarysearch()
{
int l = 1, r = (n + 1)/2;
int pos ;
while(l <= r)
{
int mid = (l + r) >> 1;

if(isok(mid))
{
pos = mid;
l = mid + 1;
}
else
r = mid - 1;
}
return pos;
}

int main()
{
while(scanf("%d",&n) && n)
{
int pre, val;
scanf("%d",&val);
pre = val;
//n--;
for( int i = 0; i < n-1; i++)
{
scanf("%d",&val);
s[i] = val - pre;
pre = val;
}

makesa();
lcp();
int ans = binarysearch();
if(ans >= 4)
printf("%d\n",ans + 1);
else
printf("0\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: