poj1743 Musical Theme

地址:http://poj.org/problem?id=1743

题目:

Musical Theme

Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 28675   Accepted: 9674

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

[email protected]

思路:

  论文上的题目,相邻数做差后对数组求后缀数组(注意此时差可能为负数,所以加上100保证非负)

  然后二分长度,check时把height分组判断即可

  

  

 1 #include <cstdlib>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <algorithm>
 5
 6 const int N = 20005;
 7 int sa[N],s[N],wa[N], wb[N], ws[N], wv[N];
 8 int rank[N], height[N];
 9
10 bool cmp(int r[], int a, int b, int l)
11 {
12     return r[a] == r[b] && r[a+l] == r[b+l];
13 }
14
15 void da(int r[], int sa[], int n, int m)
16 {
17     int i, j, p, *x = wa, *y = wb;
18     for (i = 0; i < m; ++i) ws[i] = 0;
19     for (i = 0; i < n; ++i) ws[x[i]=r[i]]++;
20     for (i = 1; i < m; ++i) ws[i] += ws[i-1];
21     for (i = n-1; i >= 0; --i) sa[--ws[x[i]]] = i;
22     for (j = 1, p = 1; p < n; j *= 2, m = p)
23     {
24         for (p = 0, i = n - j; i < n; ++i) y[p++] = i;
25         for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
26         for (i = 0; i < n; ++i) wv[i] = x[y[i]];
27         for (i = 0; i < m; ++i) ws[i] = 0;
28         for (i = 0; i < n; ++i) ws[wv[i]]++;
29         for (i = 1; i < m; ++i) ws[i] += ws[i-1];
30         for (i = n-1; i >= 0; --i) sa[--ws[wv[i]]] = y[i];
31         for (std::swap(x, y), p = 1, x[sa[0]] = 0, i = 1; i < n; ++i)
32             x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;
33     }
34 }
35
36 void calheight(int r[], int sa[], int n)
37 {
38     int i, j, k = 0;
39     for (i = 1; i <= n; ++i) rank[sa[i]] = i;
40     for (i = 0; i < n; height[rank[i++]] = k)
41         for (k?k--:0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k++);
42 }
43 bool check(int len,int x)
44 {
45     int mx=sa[1],mi=sa[1];
46     for(int i=2;i<=len;i++)
47     {
48         if(height[i]<x)
49         {
50             if(mx-mi>=x)
51                 return 1;
52             mx=mi=sa[i];
53         }
54         else
55         {
56             mx=std::max(sa[i],mx);
57             mi=std::min(sa[i],mi);
58         }
59     }
60     return mx-mi>=x;
61 }
62 int main()
63 {
64     int n;
65     while(scanf("%d",&n)&&n)
66     {
67         int x,ls,len=0;
68         scanf("%d",&ls);
69         for(int i=0;i<n-1;i++)
70             scanf("%d",&x),s[len++]=x-ls+100,ls=x;
71         s[len]=0;
72         da(s,sa,len+1,200);
73         calheight(s,sa,len);
74         int l=5,r=n/2,ans=0;
75         while(l<=r)
76         {
77             int mid=l+r>>1;
78             if(check(len,mid-1))
79                 ans=mid,l=mid+1;
80             else
81                 r=mid-1;
82         }
83         printf("%d\n",ans);
84     }
85     return 0;
86 }
时间: 2025-01-02 16:57:42

poj1743 Musical Theme的相关文章

POJ1743 Musical Theme [没做出来]

Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 27539   Accepted: 9290 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

[POJ1743] Musical Theme (后缀数组)

题目概述: 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 tim

POJ-1743 Musical Theme(最长不可重叠子串,后缀数组+二分)

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; b

【后缀数组】【二分答案】【差分】poj1743 Musical Theme

差分消除加减一个值得影响,貌似r二分上界要设成(n-2)/2?为啥? sa求不可重叠最长重复子串 给定一个字符串,求最长重复子串,这两个子串不能重叠.算法分析:这题比上一题稍复杂一点.先二分答案,把题目变成判定性问题:判断是否存在两个长度为 k 的子串是相同的,且不重叠.解决这个问题的关键还是利用height 数组.把排序后的后缀分成若干组,其中每组的后缀之间的 height 值都不小于 k. 容易看出,有希望成为最长公共前缀不小于 k 的两个后缀一定在同一组. 然后对于每组后缀,只须判断每个后

[poj1743]Musical Theme后缀数组

题意:不可重叠最长重复子串 有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题.“主题”是整个音符序列的一个子串,它需要满足如下条件: 1.长度至少为5个音符. 2.在乐曲中重复出现.(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值) 3.重复出现的同一主题不能有公共部分. 二分答案,转化为存在性判定,后缀数组问题的套路解法 1 #include <cstdlib> 2 #incl

[POJ1743]Musical Theme[SA+二分]

2009那篇论文里介绍的做法 这里面有下载链接 这个题是要转成差分序列再做的 导致我WA了一发的地方 if (Max - Min > x) return 1; 写成>=了(论文里说的距离不小于k 转成差分序列好像就要写成>) #include <cstdio> #include <iostream> #include <algorithm> using namespace std; using namespace std; int k, n, rnk[

POJ 1743 Musical Theme【SAM】

POJ1743 Musical Theme 要找长度\(\ge 5\)且出现次数\(\ge 2\)并且第一次出现和最后一次出现不重叠的最长子串. 题目条件中,如果对于两个串,在一个串的每个数上都加上相同的数之后可以得到另一个串,那么这个两个串可以被是相同的. 首先我们先得到差分数组,然后要求的就是差分数组中长度\(\ge 4\)且出现次数\(\ge 2\)并且第一次出现和最后一次出现不重叠的最长子串 我们需要知道的是每个等价类中终点的最左端和最右端的位置,即(\(firstpos,lastpos

POJ1743 (Musical Theme,后缀数组)

Links Musical Theme Time Limit: 1000MS   Memory Limit: 30000K       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 t

Musical Theme

poj1743:http://poj.org/problem?id=1743 题意: 题解: 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 const int maxn=20010; 6 char str[maxn]; 7 int wa[maxn],wb[maxn],wv[maxn],wn[maxn],a[maxn],sa[maxn]; 8 int