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数组分组,
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; }
相关文章推荐
- lightoj 1150 - Ghosts! 【BFS + 二分查找 + 判二分图完美匹配】
- BZOJ 1010 [HNOI2008]玩具装箱toy 斜率优化DP
- error: expected declaration or statement at end of input----solved
- keepalived配置
- Andrew Ng Machine Learning 专题【K-Means】
- 系统启动后更新u-boot.bin zImage
- C++继承
- 线性表的基本运算及多项式的算术运算
- struts 2配置文件的包继承
- JAVA项目出现红色叹号
- 【LeetCode】 Best Time to Buy and Sell Stock I II III IV 解题报告
- nyoj891找点
- 递归的一些经典应用
- 一个常见的错误时编写代码
- Validform 学习笔记---基础知识整理
- Android笔记---使用ViewFlipper组件实现文本上下滑动效果
- HDU 4819 二维线段树
- Android 项目(详解三)—— 数据库类
- 初识UML
- Fiddler手机抓包