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.
 
 
题解+代码:
  1 /*
2 对于结果我们是二分出来的
3 首先对于原始数据我们要处理一下,因为题目上有三个要求
4 1.长度至少为5个音符
5 2.在乐曲中重复出现(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值。)
6 3.重复出现的同一主题不能有公共部分。
7
8 我们来任意举一个例子1 2 3 2 3 4那么这个序列的输出结果应该就是3
9 因为题目上说了可能存在转调这一种情况,那么对于音乐的主曲而言,转调之后和转调之前这个主曲相邻两个部分的差距是一样的
10 那么我们就可以让它们减去上一个,或者减去下一个(这里以减去上一个为例)
11 对于样例减完之后1 1 -1 1 1 然后这就解决了转调的问题,然后只需要处理1,3要求就好了
12 对于1,3我们只需要求一下得到的这个序列中重复次数大于等于2次的主曲最长长度接可以了
13 怎么求?
14 可以用后缀数组中的height数组
15
16 设我们二分出来的答案是x,我们只需要在确定处理后的序列中有没有长度大于等于x的两段主曲
17 因为height[i]数组就是找后缀i和后缀i-1的最长前缀,而且最长前缀只会出现在i+1后缀和i-1后缀两者之中(至于为什么可以想想)
18 ,所以height数组的值就表示有两个部分的长度。满足题目要求主曲部分大于等于2次出现要求
19
20 但是要注意height数组中的最长前缀可能存在重叠部分,所以要判断
21
22 */
23 #include <iostream>
24 #include <cstdio>
25 #include <cstring>
26 #include <algorithm>
27 #include <queue>
28 using namespace std;
29 const int maxn = 20010;
30 int sa[maxn]; //SA数组,表示将S的n个后缀从小到大排序后把排好序的
31 //的后缀的开头位置顺次放入SA中
32 int x[maxn], y[maxn], c[maxn];
33 int rank[maxn], height[maxn];
34 int s[maxn];
35 bool pan(int *x,int i,int j,int k,int n)
36 {
37 int ti=i+k<n?x[i+k]:-1;
38 int tj=j+k<n?x[j+k]:-1;
39 return x[i]==x[j]&&ti==tj;
40 }
41 void build_SA(int n)
42 {
43 int *x=rank,*y=height,r=200;
44 for(int i=0; i<r; i++)c[i]=0;
45 for(int i=0; i<n; i++)c[s[i]]++;
46 for(int i=1; i<r; i++)c[i]+=c[i-1];
47 for(int i=n-1; i>=0; i--)sa[--c[s[i]]]=i;
48 r=1;
49 x[sa[0]]=0;
50 for(int i=1; i<n; i++)
51 x[sa[i]]=s[sa[i]]==s[sa[i-1]]?r-1:r++;
52 for(int k=1; r<n; k<<=1)
53 {
54 int yn=0;
55 for(int i=n-k; i<n; i++)y[yn++]=i;
56 for(int i=0; i<n; i++)
57 if(sa[i]>=k)y[yn++]=sa[i]-k;
58 for(int i=0; i<r; i++)c[i]=0;
59 for(int i=0; i<n; i++)++c[x[y[i]]];
60 for(int i=1; i<r; i++)c[i]+=c[i-1];
61 for(int i=n-1; i>=0; i--)sa[--c[x[y[i]]]]=y[i];
62 swap(x,y);
63 r=1;
64 x[sa[0]]=0;
65 for(int i=1; i<n; i++)
66 x[sa[i]]=pan(y,sa[i],sa[i-1],k,n)?r-1:r++;
67 }
68 for(int i=0; i<n; i++)rank[i]=x[i];
69 }
70 void get_height(int n)
71 {
72 int i,j,k=0;
73 for(i=1; i<=n; i++)rank[sa[i]]=i;
74 for(i=0; i<n; i++)
75 {
76 if(k)k--;
77 else k=0;
78 j=sa[rank[i]-1];
79 while(s[i+k]==s[j+k])k++;
80 height[rank[i]]=k;
81 }
82 }
83 int check(int n,int k)
84 {
85 int Max = sa[1], Min = sa[1];
86 for (int i = 2; i <= n; i++)
87 {
88 if (height[i] < k)
89 Max = Min = sa[i];
90 else
91 {
92 if (sa[i] < Min) Min = sa[i];
93 if (sa[i] > Max) Max = sa[i];
94 if (Max - Min > k) return 1;
95 }
96 }
97 return 0;
98 }
99 int main()
100 {
101 int n;
102 while (scanf("%d", &n) != EOF && n)
103 {
104 for (int i = 0; i < n; i++)
105 scanf("%d", &s[i]);
106 for (int i = n-1; i > 0; i--)
107 s[i] = s[i] - s[i-1] + 90;
108 n--;
109 for (int i = 0; i < n; i++)
110 s[i] = s[i+1];
111 s[n] = 0;
112 build_SA(n+1);
113 get_height(n);
114 int ans = -1;
115 int l = 1, r = n/2;
116 while (l <= r)
117 {
118 int mid = l + r >> 1;
119 if (check(n, mid))
120 {
121 ans = mid;
122 l = mid + 1;
123 }
124 else r = mid - 1;
125 }
126 if (ans < 4)
127 printf("0\n");
128 else printf("%d\n", ans+1);
129 }
130 return 0;
131 }
 

Musical Theme POJ - 1743 后缀数组的更多相关文章

  1. POJ 1743 后缀数组

    题目链接:http://poj.org/problem?id=1743 题意:给定一个钢琴的音普序列[值的范围是(1~88)],现在要求找到一个子序列满足 1,长度至少为5 2,序列可以转调,即存在两 ...

  2. POJ 1743 (后缀数组+不重叠最长重复子串)

    题目链接: http://poj.org/problem?id=1743 题目大意:楼教主の男人八题orz.一篇钢琴谱,每个旋律的值都在1~88以内.琴谱的某段会变调,也就是说某段的数可以加减一个旋律 ...

  3. poj 1743 后缀数组 最长不重叠子串

    Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 30941   Accepted: 10336 D ...

  4. 【POJ1743】 Musical Theme (二分+后缀数组)

    Musical Theme Description A musical melody is represented as a sequence of N (1<=N<=20000)note ...

  5. Musical Theme - poj 1743(求最大不重叠重复子串)

    题目大意: * 有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题. * “主题”是整个音符序列的一个子串,它需要满 ...

  6. POJ1743 Musical Theme(二分+后缀数组)

    题目大概是给n个数组成的串,求是否有多个“相似”且不重叠的子串的长度大于等于5,两个子串相似当且仅当长度相等且每一位的数字差都相等. 这题是传说中楼教主男人八题之一,虽然已经是用后缀数组解决不可重叠最 ...

  7. poj 1743 后缀数组 求最长不重叠重复子串

    题意:有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题. “主题”是整个音符序列的一个子串,它需要满足如下条件:1 ...

  8. [八分之一的男人]POJ - 1743 后缀数组 height分组 带详解

    题意:求最长不可重叠的相同差值子串的长度 这道题算是拖了好几个月,现在花了点时间应该搞懂了不少,尝试分析一下 我们首先来解决一个退化的版本,求最长不可重叠的相同子串(差值为0) 比如\(aabaaba ...

  9. Musical Theme POJ - 1743(后缀数组+二分)

    求不可重叠最长重复子串 对于height[i]定义为sa[i]和 sa[i-1]的最长公共前缀 这个最长公共前缀的值肯定是最大的 证明: 设rank[j] < rank[k], 则不难证明后缀j ...

随机推荐

  1. MybatisPlus多数据源及事务解决思路

    关于多数据源解决方案 目前在SpringBoot框架基础上多数据源的解决方案大多手动创建多个DataSource,后续方案有三: 继承org.springframework.jdbc.datasour ...

  2. VB基础总结

    前段时间用VB写了一个简单窗口小应用,久了不碰VB,都忘了,下面用思维导图简单总结了一些基础的东西,方便以后快速查阅.

  3. AVA编程中button按钮,actionlistener和mouseClicked区别

    在java的编程中,对于按钮button 有两个事件: 1.actionPerformed 2.mouseClicked 区别: actionPerformed:一般事件,仅侦听鼠标左键的单击事件,右 ...

  4. 如何创建一个Java项目

    目录 新建项目 项目信息配置 创建Java类 编译和运行 新建项目 首先双击eclipse进入到eclipse页面. 菜单"File"下的"New"里" ...

  5. (07)-Python3之--函数

    1.定义 函数:实现了某一特定功能.    可以重复使用. 例如: len()   功能:获取长度.input()   功能: 控制台输入print()   功能:输出 语法: def 函数名称(参数 ...

  6. js input相关事件(转载)

    1.onfocus  当input 获取到焦点时触发. 2.onblur  当input失去焦点时触发,注意:这个事件触发的前提是已经获取了焦点再失去焦点的时候才会触发该事件,用于判断标签为空.3.o ...

  7. Memcached与Redis对比及其优劣分析

    国外讨论 本文主要总结缓存Redis和Memcached的区别,总结之前先参考外国知乎上的一篇问答:<Is memcached a dinosaur in comparison to Redis ...

  8. (转载)微软数据挖掘算法:Microsoft顺序分析和聚类分析算法(8)

    前言 本篇文章继续我们的微软挖掘系列算法总结,前几篇文章已经将相关的主要算法做了详细的介绍,我为了展示方便,特地的整理了一个目录提纲篇:大数据时代:深入浅出微软数据挖掘算法总结连载,有兴趣的童鞋可以点 ...

  9. 【C++小知识】#define、enum、const的含义与用法

    一.#define 含义 define是宏定义,编译器不对其进行错误检查,在预编译阶段处理,没有作用域限制属于全局常量,在程序中编译器会对定义的常量名以数值进行替换,且每次替换都分配内存,此方法对于大 ...

  10. Codeforces Round #671 (Div. 2) (A~E)

    Link~ 题面差评,整场都在读题 A 根据奇偶性判断一下即可. #include<bits/stdc++.h> #define ll long long #define N #defin ...