题目链接

题意

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

  1. 长度至少为5个音符。
  2. 在乐曲中重复出现。(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值)
  3. 重复出现的同一主题不能有公共部分。

思路

论文里面出现的题目。

因为加上和减去同一个整数值,就可以作差,因为减出来可能是个负数,因此需要+88.

二分答案,转化为是否存在两个长度为k的子串是相同的,且不重叠。

将height数组根据k分组,使得每组的后缀之间的height值都大于等于k,有希望成为最长公共前缀不小于k的两个后缀在同一组。

要使得两个串不重叠,只要判断同一组里面最大的sa值和最小的sa值的差大于等于k,这样就可以不重叠了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 11;
int t1[N], t2[N], c[N], s[N], str[N], Hash[N], sa[N], rak[N], heigth[N], n; bool cmp(int *r, int a, int b, int l) {
return r[a] == r[b] && r[a+l] == r[b+l];
} void DA(int s[], int n, int m) {
n++;
int i, j, p, *x = t1, *y = t2;
for(i = 0; i < m; i++) c[i] = 0;
for(i = 0; i < n; i++) c[x[i] = s[i]]++;
for(i = 1; i < m; i++) c[i] += c[i-1];
for(i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;
for(j = 1; j < n; j <<= 1) {
p = 0;
for(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 < m; i++) c[i] = 0;
for(i = 0; i < n; i++) c[x[y[i]]]++;
for(i = 1; i < m; i++) c[i] += c[i-1];
for(i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i]; swap(x, y);
p = 1; x[sa[0]] = 0;
for(i = 1; i < n; i++)
x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1 : p++;
if(p >= n) break;
m = p;
}
n--;
int k = 0;
for(i = 0; i <= n; i++) rak[sa[i]] = i;
for(i = 0; i < n; i++) {
if(k) k--;
j = sa[rak[i]-1];
while(s[i+k] == s[j+k]) k++;
heigth[rak[i]] = k;
}
} bool check(int k) {
int mi = INF, ma = -INF;
for(int i = 2; i <= n; i++) {
if(heigth[i] >= k) {
mi = min(mi, min(sa[i], sa[i-1]));
ma = max(ma, max(sa[i], sa[i-1]));
if(ma - mi >= k) return 1;
} else {
mi = INF, ma = -INF;
}
} return 0;
} int main() {
while(scanf("%d", &n), n) {
for(int i = 0; i < n; i++) scanf("%d", &s[i]);
for(int i = 0; i < n; i++) s[i] = s[i+1] - s[i] + 88;
int m = 177;
n--;
s[n] = 0;
DA(s, n, m);
int l = 0, r = n, ans = l;
while(l <= r) {
int mid = (l + r) >> 1;
if(check(mid)) l = mid + 1, ans = mid;
else r = mid - 1;
}
if(ans < 4) puts("0");
else printf("%d\n", ans + 1);
}
return 0;
}

POJ 1743:Musical Theme(后缀数组+二分)的更多相关文章

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

    题目链接: Poj  1743 Musical Theme 题目描述: 给出一串数字(数字区间在[1,88]),要在这串数字中找出一个主题,满足: 1:主题长度大于等于5. 2:主题在文本串中重复出现 ...

  2. Poj 1743 Musical Theme(后缀数组+二分答案)

    Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 28435 Accepted: 9604 Descri ...

  3. POJ 1743 Musical Theme ——后缀数组

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

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

    Musical ThemeTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://poj.org/problem?id=1743 Description ...

  5. poj 1743 Musical Theme (后缀数组+二分法)

    Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 16162   Accepted: 5577 De ...

  6. [poj 1743] Musical Theme 后缀数组 or hash

    Musical Theme 题意 给出n个1-88组成的音符,让找出一个最长的连续子序列,满足以下条件: 长度大于5 不重叠的出现两次(这里的出现可以经过变调,即这个序列的每个数字全都加上一个整数x) ...

  7. POJ 1743 Musical Theme ( 后缀数组 && 最长不重叠相似子串 )

    题意 : 给 n 个数组成的串,求是否有多个“相似”且不重叠的子串的长度大于等于5,两个子串相似当且仅当长度相等且每一位的数字差都相等. 分析 :  根据题目对于 “ 相似 ” 串的定义,我们可以将原 ...

  8. POJ.1743.Musical Theme(后缀数组 倍增 二分 / 后缀自动机)

    题目链接 \(Description\) 给定一段数字序列(Ai∈[1,88]),求最长的两个子序列满足: 1.长度至少为5 2.一个子序列可以通过全部加或减同一个数来变成另一个子序列 3.两个子序列 ...

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

    二分长度k 长度大于等于k的分成一组 每组sa最大的和最小的距离大于k 说明可行 #include <cstdio> #include <cstring> #include & ...

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

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

随机推荐

  1. 浅谈 Swift 中的 Optionals

    input[type="date"].form-control,.input-group-sm>input[type="date"].input-grou ...

  2. js 动态生成button 并设置click事件

    <div id="MyDiv"></div> <script> function AddButton() { var MyDiv =docume ...

  3. Token的设计(2)

    词法分析 Token的几个种类 前端的第一步就是词法分析, 这个过程通俗来讲就是将源代码转化为一串Tokens. 所以首先应该想到的是, 到底该有哪几种类型的Token ? 关于这个问题我已经想过了, ...

  4. qt部分类释义

    如果测试错误,输出包含源码的警告信息 Q_ASSERT Qtime最后一次star()或restar()到现在的毫秒数 QTime::elapsed QMetaObject::invokeMethod ...

  5. windows下,Qt Creator 中javascript调试器安装并使用

    最开始使用Qt Creator时,想使用断点来调试javascript代码.但在按下debug键后,却提示调试器未配置,让我比较郁闷. 好了,郁闷的是说了,咱们来说说高兴的.要Qt Creator调试 ...

  6. winform实现DataGridView全选

    之前写过,一时想不起来就在网上找了一些.结果感觉好麻烦.于是就自己打开之前做过的功能.找到源码. private void CheckDatabasexuan() { DataGridViewChec ...

  7. UBUNTU 16.04 + CUDA8.0 + CUDNN6.0 + OPENCV3.2 + MKL +CAFFE + tensorflow

    首先说一下自己机子的配置 CPU:Intel(R) Core(TM) i5-5600 CUP @3.20GHz *4 GPU : GTX 1060 OS : 64bit Ubuntu16.04LTS ...

  8. NFS服务设置

    1.安装NFS服务sudo apt-get install nfs-common nfs-kernel-server 2.配置NFS服务首先需要手动编辑/etc/exports配置文件 权限参数说明如 ...

  9. Ceph OpenSSL

    Ceph OpenSSL 1. SSL介绍 SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信 ...

  10. 使用mingw 对libcURL,openSSL,zLib交叉编译

    使用mingw 对libcURL,openSSL,zLib交叉编译   将三个库解压到同一目录下 比如取目录名为 "source" 的目录   提前安装active-perl 配置 ...