poj 1743 男人八题之后缀数组求最长不可重叠最长重复子串
| Time Limit: 1000MS | Memory Limit: 30000K | |
| Total Submissions: 14874 | Accepted: 5118 |
Description
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 last test case is followed by one zero.
Output
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
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 男人八题之后缀数组求最长不可重叠最长重复子串的更多相关文章
- POJ 1743 [USACO5.1] Musical Theme (后缀数组+二分)
洛谷P2743传送门 题目大意:给你一个序列,求其中最长的一对相似等长子串 一对合法的相似子串被定义为: 1.任意一个子串长度都大于等于5 2.不能有重叠部分 3.其中一个子串可以在全部+/-某个值后 ...
- poj 1737男人八题之一 orz ltc
这是楼教主的男人八题之一.很高兴我能做八分之一的男人了. 题目大意:求有n个顶点的连通图有多少个. 解法: 1. 用总数减去不联通的图(网上说可以,我觉得时间悬) 2. 用动态规划(数学递推) ...
- POJ 1743:Musical Theme(后缀数组+二分)
题目链接 题意 有N个音符的序列来表示一首乐曲,每个音符都是1到88范围内的整数,现在要找一个重复的主题."主题"是整个音符序列的一个子串,它需要满足如下条件: 长度至少为5个音符 ...
- poj 1741 楼教主男人八题之中的一个:树分治
http://poj.org/problem? id=1741 Description Give a tree with n vertices,each edge has a length(posit ...
- poj 1743 二分答案+后缀数组 求不重叠的最长重复子串
题意:给出一串序列,求最长的theme长度 (theme:完全重叠的子序列,如1 2 3和1 2 3 or 子序列中每个元素对应的差相等,如1 2 3和7 8 9) 要是没有差相等这个条件那就好办 ...
- POJ1742 Coins(男人八题之一)
前言 大名鼎鼎的男人八题,终于见识了... 题面 http://poj.org/problem?id=1742 分析 § 1 多重背包 这很显然是一个完全背包问题,考虑转移方程: DP[i][j]表示 ...
- Cogs 1714. [POJ1741][男人八题]树上的点对(点分治)
[POJ1741][男人八题]树上的点对 ★★★ 输入文件:poj1741_tree.in 输出文件:poj1741_tree.out 简单对比 时间限制:1 s 内存限制:256 MB [题目描述] ...
- POJ 3294 UVA 11107 Life Forms 后缀数组
相同的题目,输出格式有区别. 给定n个字符串,求最长的子串,使得它同时出现在一半以上的串中. 不熟悉后缀数组的童鞋建议先去看一看如何用后缀数组计算两个字符串的最长公共子串 Ural1517 这道题的思 ...
- 【POJ2774】Long Long Message(后缀数组求Height数组)
点此看题面 大致题意: 求两个字符串中最长公共子串的长度. 关于后缀数组 关于\(Height\)数组的概念以及如何用后缀数组求\(Height\)数组详见这篇博客:后缀数组入门(二)--Height ...
随机推荐
- docker学习笔记2:容器操作
一.列出主机上已经创建的容器 docker ps -a 二.创建交互式容器 命令: docker run -i -t ubuntu /bin/bash 其中-i -t 表示创建一个提供交互式shell ...
- JVM参数说明(转)
做了这么多年java,自以为算是熟悉,其实还差得远,啥也别说了,还是踏踏实实地学吧.今天总结一下常用的JVM的启动参数. 参数类别 参数项 说明 标准参数(-,所有的JVM实现都必须实现这些参数的功能 ...
- 基于visual Studio2013解决C语言竞赛题之0803报数
题目
- ADO.NET 对象 结构图
- boost ini
#include <boost/property_tree/ptree.hpp>#include <boost/property_tree/ini_parser.hpp> .. ...
- [Codecademy] HTML&CSS 第七课:CSS: An Overview
本文出自 http://blog.csdn.net/shuangde800 [Codecademy] HTML && CSS课程学习目录 --------------------- ...
- Linux Kbuild工作原理分析(以DVSDK生成PowerVR显卡内核模块为例)
一.引文 前篇博文<Makefile之Linux内核模块的Makefile写法分析>,介绍了Linux编译生成内核驱动模块的Makefile的写法,但最近在DVSDK下使用Linux2.6 ...
- iOS- 如何集成支付宝
链接地址:http://www.cnblogs.com/qingche/p/3556365.html 现在不少app内都集成了支付宝功能 使用支付宝进行一个完整的支付功能,大致有以下步骤: 1&g ...
- perl eval
eval 表达式: eval 块: eval 在第一种形式,通常称为一个字符串eval EXPR 返回值是被解析的和被执行的作为一个小小的Perl程序. 表达式的值(是它本身决定的在标量上下文环境)是 ...
- 【小白的java成长系列】——javakeyword
准备出一个系列的内容啦,今天就从keyword開始说起吧~ 类型 keyword 说明 keyword 说明 訪问控制权限 public 公共的.公开的. protected 受保护的.用来修饰属性或 ...