Musical Theme
Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 14874   Accepted: 5118

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

 

给定一个正整数N(N<=20000),然后是N个整数xi,(1<=xi<=88, 1<=i<=N)组成一个有序的整数序列;问这个序列中存在的最长一个符合条件的子序列长度是多少,符合的条件是

1、 子序列A长度至少为5;

2、 有另外一个子序列B,且A、B二者没有相交部分  不重叠;

3、 A,B的长度一样 AB相同或者 A的所有元素加上减去一个相同的数能变成B;

思路:

如果2个串满足上面条件 那么他们的每个元素a[i]-a[i-1]   即相邻的元素相减 得到的差值也应该是相同的    注意n个数的差中只要有n-1个数相同 (所以我代码中最后结果+1)那么这2个字串就是符合题意的

之后就是用后缀数组求不可重叠最长重复子串了

首先由二分答案的方法将问题变成判定性的:长度大于k的重复字串有没有?然后将height数组分组,每组内的后缀之间的height都要大于k,如果每组内的后缀之间的最长公共前缀有大于k的而且这两个后缀的sa[]之差大于k就说明存在长度至少为k的不重复子串。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<cstring>
using namespace std; const int nMax =1000012; int num[nMax];
int sa[nMax], rank[nMax], height[nMax];
int wa[nMax], wb[nMax], wv[nMax], wd[nMax];
int mmin(int a,int b)
{
if(a>b) return b;
return a;
}
int cmp(int *r, int a, int b, int l)
{
return r[a] == r[b] && r[a+l] == r[b+l];
} void da(int *r, int n, int m){ // 倍增算法 r为待匹配数组 n为总长度 m为字符范围
int i, j, p, *x = wa, *y = wb, *t;
for(i = 0; i < m; i ++) wd[i] = 0;
for(i = 0; i < n; i ++) wd[x[i]=r[i]] ++;
for(i = 1; i < m; i ++) wd[i] += wd[i-1];
for(i = n-1; i >= 0; i --) sa[-- wd[x[i]]] = i;
for(j = 1, p = 1; p < n; j *= 2, m = p){
for(p = 0, i = n-j; i < n; i ++) y[p ++] = i;
for(i = 0; i < n; i ++) if(sa[i] >= j) y[p ++] = sa[i] - j;
for(i = 0; i < n; i ++) wv[i] = x[y[i]];
for(i = 0; i < m; i ++) wd[i] = 0;
for(i = 0; i < n; i ++) wd[wv[i]] ++;
for(i = 1; i < m; i ++) wd[i] += wd[i-1];
for(i = n-1; i >= 0; i --) sa[-- wd[wv[i]]] = y[i];
for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i ++){
x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1: p ++;
}
}
} void calHeight(int *r, int n){ // 求height数组。
int i, j, k = 0;
for(i = 1; i <= n; i ++) rank[sa[i]] = i; // 1->n
for(i = 0; i < n; i++){
for(k ? k -- : 0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k ++);
height[rank[i]] = k;
}
} int Log[nMax];
int best[20][nMax];//best[i][j] 表示从j开始的长度为2的i次方的一段元素的最小值
void initRMQ(int n)
{//初始化RMQ
int i,j;
for(i = 1; i <= n ; i ++) best[0][i] = height[i];
for(i = 1; i <= Log[n] ; i ++)
{
int limit = n - (1<<i) + 1;
for(j = 1; j <= limit ; j ++)
{
best[i][j] = mmin(best[i-1][j] , best[i-1][j+(1<<i>>1)]);
}
}
}
int lcp(int a,int b) {//询问a,b后缀的最长公共前缀
a = rank[a]; b = rank[b];
if(a > b) swap(a,b);
a ++;
int t = Log[b - a + 1];
return mmin(best[t][a] , best[t][b - (1<<t) + 1]);
} void get_log()
{
int i;
Log[0] = -1;
for(i=1;i<=nMax;i++)
{ // 求log2,这么强大的位运算。。
Log[i]=(i&(i-1))?Log[i-1]:Log[i-1] + 1 ;
}
}
char str[nMax];
int ans[nMax];
int n;
int a[nMax];
int solve(int x)
{
///注意通过判断sa[i]-sa[i-1]>=k决定不重复长度是否大于k是不行的 因为有可能有好几个重复的排在一起
///对于每个都不大于k 但是最后一个和第一个的距离是大于k的
///注意sa[i],sa[i-1]不一定哪个大那个小
int i,mx,mn;
mx=0,mn=nMax;
for(i=1;i<=n;i++)
{
if(height[i]>=x)
{
mx=max(mx,sa[i]);
mn=min(mn,sa[i]);
if(mx-mn>=x) return 1;
}
else
{
mx=mn=sa[i];
}
} return 0;
} int main()
{
int i,j;
get_log();
while(scanf("%d",&n)!=EOF)
{
if(!n) break;
for(i=0;i<n;i++) scanf("%d",&a[i]);
// n--;
for(i=1;i<n;i++)
{
num[i]=a[i]-a[i-1]+100;//加100防止出现负数
}
num[n]=0;
da(num,n+1,300);//这里要开大一点 300
calHeight(num,n);
initRMQ(n);
/*
for(i=0; i<n+1; i++) // rank[i] : suffix(i)排第几
printf("rank[%d] = %d\n",i,rank[i]);
printf("\n");
for(i=0; i<n+1; i++) // sa[i] : 排在第i个的是谁
printf("sa[%d] = %d\n",i,sa[i]);
*/
int left,right,mx=0,mid;
left=4;right=n/2+1;
while(left<=right)
{
mid=(left+right)/2;
if(solve(mid)&&mid>mx)
{
mx=mid;
left=mid+1;
}
else
{
right=mid-1;
}
}
if(mx==0) {printf("0\n");continue;}
printf("%d\n",mx+1);
}
return 0;
}

poj 1743 男人八题之后缀数组求最长不可重叠最长重复子串的更多相关文章

  1. POJ 1743 [USACO5.1] Musical Theme (后缀数组+二分)

    洛谷P2743传送门 题目大意:给你一个序列,求其中最长的一对相似等长子串 一对合法的相似子串被定义为: 1.任意一个子串长度都大于等于5 2.不能有重叠部分 3.其中一个子串可以在全部+/-某个值后 ...

  2. poj 1737男人八题之一 orz ltc

    这是楼教主的男人八题之一.很高兴我能做八分之一的男人了. 题目大意:求有n个顶点的连通图有多少个. 解法: 1.  用总数减去不联通的图(网上说可以,我觉得时间悬) 2.    用动态规划(数学递推) ...

  3. POJ 1743:Musical Theme(后缀数组+二分)

    题目链接 题意 有N个音符的序列来表示一首乐曲,每个音符都是1到88范围内的整数,现在要找一个重复的主题."主题"是整个音符序列的一个子串,它需要满足如下条件: 长度至少为5个音符 ...

  4. poj 1741 楼教主男人八题之中的一个:树分治

    http://poj.org/problem? id=1741 Description Give a tree with n vertices,each edge has a length(posit ...

  5. poj 1743 二分答案+后缀数组 求不重叠的最长重复子串

    题意:给出一串序列,求最长的theme长度 (theme:完全重叠的子序列,如1 2 3和1 2 3  or  子序列中每个元素对应的差相等,如1 2 3和7 8 9) 要是没有差相等这个条件那就好办 ...

  6. POJ1742 Coins(男人八题之一)

    前言 大名鼎鼎的男人八题,终于见识了... 题面 http://poj.org/problem?id=1742 分析 § 1 多重背包 这很显然是一个完全背包问题,考虑转移方程: DP[i][j]表示 ...

  7. Cogs 1714. [POJ1741][男人八题]树上的点对(点分治)

    [POJ1741][男人八题]树上的点对 ★★★ 输入文件:poj1741_tree.in 输出文件:poj1741_tree.out 简单对比 时间限制:1 s 内存限制:256 MB [题目描述] ...

  8. POJ 3294 UVA 11107 Life Forms 后缀数组

    相同的题目,输出格式有区别. 给定n个字符串,求最长的子串,使得它同时出现在一半以上的串中. 不熟悉后缀数组的童鞋建议先去看一看如何用后缀数组计算两个字符串的最长公共子串 Ural1517 这道题的思 ...

  9. 【POJ2774】Long Long Message(后缀数组求Height数组)

    点此看题面 大致题意: 求两个字符串中最长公共子串的长度. 关于后缀数组 关于\(Height\)数组的概念以及如何用后缀数组求\(Height\)数组详见这篇博客:后缀数组入门(二)--Height ...

随机推荐

  1. 浅尝key-value数据库(一)——一览NoSQL

    浅尝key-value数据库(一)——一览NoSQL 最近由于一个项目的关系,研究了一下key-value数据库这个最近很火的概念.本系列从项目需求的角度分析并测试了几个key-value数据库的性能 ...

  2. The Apache™ Batik Project

    Apache(tm) Batik SVG Toolkit - a Java-based toolkit for applications or applets that want to use ima ...

  3. c++怎样让返回对象的函数不调用拷贝构造函数

    我们知道拷贝构造函数有两种“默默”的方式被调用 1. 想函数传入 值参数 2. 函数返回 值类型 今天我们讨论函数返回值类型的情况. 得到结论是 1. 当对象有拷贝构造函数(系统为我们生成.或者我们自 ...

  4. Python 3语法小记(四)字典 dictionary

    字典是Python里面一种无序存储结构,存储的是键值对 key - value.关键字应该为不可变类型,如字符串.整数.包含不可变对象的元组. 字典的创建很简单,用 d = {key1 : value ...

  5. windows api 梳理

    PathMatchSpec Function Searches a string using a Microsoft MS-DOS wild card match type. Syntax BOOL  ...

  6. 云计算:创业的好时机——上海够快网络科技有限公司总经理蒋烁淼专访(评价阿里云的OSS的4个优点)(够快科技正式宣布已成功挂牌新三板)

    云存储是云计算目前的热点之一,Dropbox.Box等产品的风靡,公司因此获得极高估值,都印证了这一点.但云存储对技术和资金要求都比较高,竞争也非常激烈,挑战巨大.国外云存储公司有亚马逊的云平台作为支 ...

  7. 用c++开发基于tcp协议的文件上传功能

    用c++开发基于tcp协议的文件上传功能 2005我正在一家游戏公司做程序员,当时一直在看<Windows网络编程> 这本书,把里面提到的每种IO模型都试了一次,强烈推荐学习网络编程的同学 ...

  8. 四个流行的Java连接池之Proxool篇

    Proxool是一个JavaSQL Driver驱动程序,提供了对你选择的其它类型的驱动程序的连接池封装.可以非常简单的移植到现存的代码中.完全可配置.快速,成熟,健壮.可以透明地为你现存的JDBC驱 ...

  9. Swift - 使用MapKit显示地图,并在地图上做标记

    通过使用MapKit可以将地图嵌入到视图中,MapKit框架除了可以显示地图,还支持在地图上做标记. 1,通过mapType属性,可以设置地图的显示类型 MKMapType.Standard :标准地 ...

  10. sql server日期字段值的比较

    sql server中对日期字段值的比较 sql server中对日期字段的比较方式有多种,介绍几种常用的方式:用northwind库中的employees表作为用例表.1.between...and ...