您的位置:首页 > 其它

usaco 5.1 Musical Themes(KMP或DP)

2012-09-21 17:22 344 查看
Musical Themes

Brian Dean

A musical melody is represented as a sequence of N (1 <= N <= 5000) 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 "theme", 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!

PROGRAM NAME: theme

INPUT FORMAT

The first line of the input file contains the integer N. Each subsequent line (except potentially the last) contains 20 integers representing the sequence of notes. The last line contains the remainder of the notes,
potentially fewer than 20.

SAMPLE INPUT (file theme.in)

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

OUTPUT FORMAT

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 OUTPUT (file theme.out)

5

[The five-long theme is the last five notes of the first line and the first five notes of the second]

题意:给你一个数列,问数列中差值关系相同的两个子串的最大长度

分析:一开始想到的办法就是把相邻的两个数相减,那么只要找到差值序列的两个相同子序列就行

然后就是枚举一个子序列,用KMP找另一个子序列,最后看题解发现这种方法弱爆了T_T

题解的方法是DP

如下

设f[i,j]为两段重复旋律的开头为i和j时的最大长度。

则:f[i,j]=min(f[i-1,j-1]+1,i-j) 当s[i]==s[j]时

=1 当s[i]<>s[j]时

DP方法:

/*
ID: 15114582
PROG: theme
LANG: C++
*/
#include<cstdio>
#include<iostream>
using namespace std;
const int mm=5555;
int a[mm],s[mm],f[mm];
int i,j,k,n,ans;
int main()
{
    freopen("theme.in","r",stdin);
    freopen("theme.out","w",stdout);
    while(~scanf("%d",&n))
    {
        for(i=0;i<n;++i)
            scanf("%d",&a[i]);
        for(i=1;i<n;++i)
            s[i]=a[i-1]-a[i];
        ans=0;
        for(i=1;i<n;++i)
            for(j=n-1;j>i+ans;--j)
            {
                if(s[i]==s[j])f[j]=min(f[j-1]+1,j-i+1);
                else f[j]=0;
                ans=max(ans,f[j]+1);
            }
        if(ans<5)ans=0;
        printf("%d\n",ans);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: