[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 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:

  1. is at least five notes long
  2. appears (potentially transposed -- see below) again somewhere else in the piece of music
  3. 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.

  给你一段乐章,乐章由n个音符组成,这些音符由1..88的整数表示。现在你需要找出最长的一段旋律,使得这一段旋律至少有5个音符,至少出现过两次,且这两次的位置不相交(如果两段旋律经过变调后是一样的,那么这两段旋律可以看成出现过两次)。

  • 输入格式:

  输入包含多组数据,每组数据的第一行包括一个整数n,表示乐章的长度。接下来一行包括n个整数,表示每个音符。

  • 输出格式:

  输出一个整数,表示满足题意的最长的旋律的长度。

  • 样例输入:

  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

  • 样例输出:

  5

  • 思路:

  表示...字符串的题真心鬼畜。半天%完罗穗骞的《后缀数组——处理字符串的有力工具》后,彻底滚粗(kmp,心中永远的痛)。

  先做完了UOJ#35的模板题,又调了半天,内心是崩溃的。

  于是开始lg这道题。

  

  一道后缀自动机的模板题。用相邻两个数的差构造新的串,对新串用后缀数组lg一下,然后二分一下求不相交子串的最大长度。

  注意n=1的情况(可以和n<10的情况一起判了)。

  

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 const int MAXN = 20005;
 6 int s[MAXN], sx[MAXN], sy[MAXN], ssum[MAXN], sa[MAXN], rk[MAXN], h[MAXN];
 7 inline bool cmp(int* y, int i, int j, int k) {
 8     return y[i] == y[j] && y[i + k] == y[j + k];
 9 }
10
11 void getsa(int n, int m) {
12     int i, j, p, *x = sx, *y = sy;
13     for(i = 0; i < m; ++i) ssum[i] = 0;
14     for(i = 0; i < n; ++i) ++ssum[x[i] = s[i]];
15     for(i = 1; i < m; ++i) ssum[i] += ssum[i - 1];
16     for(i = n - 1; ~i; --i) sa[--ssum[x[i]]] = i;
17     for(p = j = 1; p < n; j <<= 1, m = p) {
18         for(p = 0, i = n - j; i < n; ++i) y[p++] = i;
19         for(i = 0; i < n; ++i) if(sa[i] >= j) y[p++] = sa[i] - j;
20         for(i = 0; i < m; ++i) ssum[i] = 0;
21         for(i = 0; i < n; ++i) ++ssum[x[y[i]]];
22         for(i = 1; i < m; ++i) ssum[i] += ssum[i - 1];
23         for(i = n - 1; ~i; --i) sa[--ssum[x[y[i]]]] = y[i];
24         swap(x, y); x[sa[0]] = 0;
25         for(p = i = 1; i < n; ++i) x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++;
26     }
27 }
28
29 void geth(int n) {
30     int j, k = 0;
31     for(int i = 1; i <= n; ++i) rk[sa[i]] = i;
32     for(int i = 0; i < n; h[rk[i++]] = k)
33         for(k ? k-- : 0, j = sa[rk[i] - 1]; s[i + k] == s[j + k]; ++k);
34 }
35
36 int solve(int x, int n) {
37     int i = 2, minh, maxh;
38     while(1) {
39         while(i <= n && h[i] < x) ++i;
40         if(i > n) break;
41         maxh = minh = sa[i - 1];
42         while(i <= n && h[i] >= x) {
43             minh = min(minh, sa[i]); maxh = max(maxh, sa[i++]);
44         }
45         if(maxh - minh > x) return true;
46     }
47     return false;
48 }
49
50 int main() {
51     int n;
52     while(~scanf("%d", &n) && n) {
53         memset(sx, 0, sizeof(sx));
54         memset(sy, 0, sizeof(sy));
55         memset(sx, 0, sizeof(sa));
56         memset(ssum, 0, sizeof(ssum));
57         for(int i = 0; i < n; ++i) scanf("%d", s + i);
58         if(--n < 9) { puts("0"); continue; }
59         for(int i = 0; i < n; ++i) s[i] = s[i + 1] - s[i] + 90;
60         s[n] = 0;
61         getsa(n + 1, 200); geth(n);
62         int l = 1, r = (n >> 1) + 1;
63         while(l < r - 1) {
64             int mid = l + r >> 1;
65             if(solve(mid, n)) l = mid;
66             else r = mid;
67         }
68         printf("%d\n", l < 4 ? 0 : r);
69     }
70     return 0;
71 }

  (话说论文里的变量名好奇怪)

  

  抱歉博客更晚了,以后应该可以按时更新。

时间: 2024-10-26 12:13:52

[POJ1743] Musical Theme (后缀数组)的相关文章

[poj1743]Musical Theme后缀数组

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

poj 1743 Musical Theme(后缀数组)

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

POJ 1743 Musical Theme 后缀数组 最长重复不相交子串

Musical ThemeTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://poj.org/problem?id=1743 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

POJ - 1743 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 music

Poj 1743 Musical Theme (后缀数组+二分)

题目链接: Poj  1743 Musical Theme 题目描述: 给出一串数字(数字区间在[1,88]),要在这串数字中找出一个主题,满足: 1:主题长度大于等于5. 2:主题在文本串中重复出现(或者经过调转出现,调转是主题同时加上或者减去同一个整数) 3:重复主题不能重叠 解题思路: 求调转重复出现的子串,那么主题之间的差值一定是不变的.可以求文本串s中相邻两个数的差值,重新组成一个新的文本串S,然后找S后缀串中最长公共不重叠前缀.rank相邻的后缀串,公共前缀一定最长,但是有可能重叠.

poj 1743 Musical Theme 后缀数组

题目链接 做出公差后找出最长不重叠子序列的长度. 后缀数组的模板, 二分长度k然后将height数组分组, 判断每一组内sa的最大值-sa的最小值是否大于等于k, 如果大于等于k则满足. 1 #include <iostream> 2 #include <vector> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #include <cmath>

POJ 1743 Musical Theme ——后缀数组

[题目分析] 其实找最长的不重叠字串是很容易的,后缀数组+二分可以在nlogn的时间内解决. 但是转调是个棘手的事情. 其实只需要o(* ̄▽ ̄*)ブ差分就可以了. 背板题. [代码] #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #

POJ 1743 Musical Theme 后缀数组 不可重叠最长重复子串

二分长度k 长度大于等于k的分成一组 每组sa最大的和最小的距离大于k 说明可行 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 20010; int s[maxn]; int sa[maxn]; int t[maxn], t2[maxn], c[maxn]; int rank[maxn], height[maxn]; void

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