http://poj.org/problem?id=1743

这题是一道后缀数组的经典例题:求不可重叠最长重复子串。

题意:

有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题。“主题”是整个音符序列的一个子串,它需要满足如下条件:
1.长度至少为5个音符。
2.在乐曲中重复出现。(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值)
3.重复出现的同一主题不能有公共部分。

题解:

因为可能同时加上或减去一个数,所以首先要作差比较。将后一个数减去前一个数得到新的数列c。

注意:例如1 2 3 4 5 2 3 4 5 6 变为 1 1 1 1 1 -3 1 1 1 1 ,重复子串的第一位是会变化的,最后要+1。

二分重复子串的长度k,然后判断它是否可行。

截自论文的图:

注意(我打的时候犯的错误):

1.分组的时候忽略了最后一组的判断。

2.因为判断的重复子串长度比真实长度小1,所以要判断位置x-y>k而不是>=k

对于这个问题的一组debug数据:1 2 3 4 5 1 2 3 4 5 1 ans=5

3.rk[i]不能等于0,至少>=1,因为我的模板没有第二关键字的那些的rk补成0了

4.看到评论里很多人犯了的错误:k最少是5,否则输出0

贴几组数据(debug好帮手):

input:

12
1 2 3 4 5 6 7 8 9 10 11 12
0

11
1 1 1 1 1 1 1 1 1 1 1

9
1 1 1 1 1 1 1 1 1

11
1 2 3 5 4 1 2 3 5 4 1

33
3 2 1 1 2 1 2 3 2 2 3 3 2 2 1 2 1 2 2 2 1 3 1 1 1 2 2 3 1 2 1 1 2

1
100

300
48 15 74 57 17 52 51 20 86 85 24 19 23 34 81 54 12 3 86 41 45 64 23 32 18 17 68 43 83 86

61 22 48 47 50 21 1 12 19 16 78 21 64 27 71 50 65 42 68 11 30 25 45 72 23 44 10 81 36 39

19 46 45 34 8 87 42 45 1 12 67 28 62 13 88 19 71 42 65 42 60 83 86 49 45 72 31 56 10 9

12 35 75 70 45 14 64 55 50 17 17 20 51 28 70 44 45 27 16 26 87 49 58 40 57 35 12 18 35

57 30 56 29 31 40 34 23 53 34 16 73 27 84 54 75 57 6 20 13 35 8 18 63 17 66 52 41 15 20

54 3 57 22 20 85 19 24 54 63 41 82 32 57 43 76 22 11 21 54 16 61 27 16 42 39 25 2 44 1

39 12 34 83 45 14 28 61 19 72 42 79 49 34 56 41 35 36 14 11 17 78 28 44 27 26 49 40 35

18 57 56 31 34 53 16 27 54 57 20 35 18 17 52 15 31 14 13 36 27 22 5 44 43 18 21 40 3 14

41 44 7 22 5 4 39 2 41 44 7 6 41 28 19 30 9 8 3 14 29 12 31 26 21 32 15 6 29 36 43 22 1

4 15 38 13 8 7 22 29 4 19 26 41 28 19 18 21 4 27 22 25 20 39 18 17 28 7 6 37 4

22
1 2 3 2 1 2 3 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1

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

output:

6
5
0
5
5
0
22
7
5

代码:

 //poj1743
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std; const int N=,INF=(int)1e9;
int n,a[N],c[N],sa[N],rk[N],Rs[N],y[N],wr[N],h[N]; int minn(int x,int y){return x<y ? x:y;}
int maxx(int x,int y){return x>y ? x:y;} void get_sa(int cl,int m)
{
for(int i=;i<=cl;i++) rk[i]=c[i];//c[i]必须>=1
for(int i=;i<=m;i++) Rs[i]=;
for(int i=;i<=cl;i++) Rs[rk[i]]++;
for(int i=;i<=m;i++) Rs[i]+=Rs[i-];
for(int i=cl;i>=;i--) sa[Rs[rk[i]]--]=i; int ln=,p=;
while(p<cl)
{
int k=;
for(int i=cl-ln+;i<=cl;i++) y[++k]=i;
for(int i=;i<=cl;i++)
if(sa[i]>ln) y[++k]=sa[i]-ln;
for(int i=;i<=cl;i++)
wr[i]=rk[y[i]]; for(int i=;i<=m;i++) Rs[i]=;
for(int i=;i<=cl;i++) Rs[wr[i]]++;
for(int i=;i<=m;i++) Rs[i]+=Rs[i-];
for(int i=cl;i>=;i--) sa[Rs[wr[i]]--]=y[i]; for(int i=;i<=cl;i++) wr[i]=rk[i];
for(int i=cl+;i<=cl+ln;i++) wr[i]=;//debug:rk[i]不能等于0的原因:这里给没有第二关键字的补0了。
p=;rk[sa[]]=;
for(int i=;i<=cl;i++)
{
if(wr[sa[i]]!=wr[sa[i-]] || wr[sa[i]+ln]!=wr[sa[i-]+ln]) p++;//debug '!='
rk[sa[i]]=p;
}
ln*=;m=p;//debug
}
sa[]=;rk[]=;
} void get_height(int cl)
{
int k=;
for(int i=;i<=cl;i++) if(rk[i]!=)
{
int j=sa[rk[i]-];
if(k) k--;
while(c[i+k]==c[j+k] && i+k<=cl && j+k<=cl) k++;
h[rk[i]]=k;
}
h[]=;
} bool check(int cl,int k)
{
int fir=,mn=INF,mx=;
for(int i=;i<=cl;i++)
{
if(h[i]<k)
{
if(mx-mn>k) return ;//debug:>=改成>才能保证差值不重复的情况下音符也不重复(第一个音符没有算进去)
fir=i;mn=INF;mx=;
}
else
{
mn=minn(mn,sa[i-]);
mx=maxx(mx,sa[i-]); }
mn=minn(mn,sa[i]);
mx=maxx(mx,sa[i]);
}
if(mx-mn>k) return ;//debug:最后一组不可忽略。
return ;
} int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
while()
{
scanf("%d",&n);
if(!n) return ;
int mx=-,pre=,mn=INF;
for(int i=;i<=n;i++)
{
int x;
scanf("%d",&x);
c[i]=x-pre;
pre=x;
mx=maxx(mx,c[i]);
mn=minn(mn,c[i]);
}
for(int i=;i<=n;i++) c[i]=c[i]-mn+;//debug 因为rk[i]不能=0,c[i]也不能=0
mx=mx-mn+;
get_sa(n,mx);
get_height(n);
int l=,r=n;
while(l<r)
{
int mid=(l+r+)/;
if(check(n,mid-)) l=mid;
else r=mid-;
}
if(l>=) printf("%d\n",l);
else printf("0\n");
}
return ;
}

【poj1743-Musical Theme】不可重叠最长重复子串-后缀数组的更多相关文章

  1. poj 1743 Musical Theme(最长重复子串 后缀数组)

    poj 1743 Musical Theme(最长重复子串 后缀数组) 有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复 ...

  2. POJ-1743 Musical Theme 字符串问题 不重叠最长重复子串

    题目链接:https://cn.vjudge.net/problem/POJ-1743 题意 给一串整数,问最长不可重叠最长重复子串有多长 注意这里匹配的意思是匹配串的所有元素可以减去或者加上某个值 ...

  3. POJ 1743 Musical Theme(不可重叠最长重复子串)

    题目链接:http://poj.org/problem?id=1743 题意:有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一 ...

  4. poj 1743 男人八题之后缀数组求最长不可重叠最长重复子串

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

  5. poj 2774 最长公共子串 后缀数组

    Long Long Message Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 25752   Accepted: 10 ...

  6. 【POJ1743】不可重叠最长重复子串

    题意:求一个字符串里两个不重叠的最长重复子串 代码如下: #include<cstdio> #include<cstdlib> #include<cstring> ...

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

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

  8. POJ 2774 Long Long Message [ 最长公共子串 后缀数组]

    题目:http://poj.org/problem?id=2774 Long Long Message Time Limit: 4000MS   Memory Limit: 131072K Total ...

  9. 【codevs3160】最长公共子串 后缀数组

    题目描述 给出两个由小写字母组成的字符串,求它们的最长公共子串的长度. 输入 读入两个字符串 输出 输出最长公共子串的长度 样例输入 yeshowmuchiloveyoumydearmotherrea ...

随机推荐

  1. 掘金 Android 文章精选合集

    掘金 Android 文章精选合集 掘金官方 关注 2017.07.10 16:42* 字数 175276 阅读 50053评论 13喜欢 669 用两张图告诉你,为什么你的 App 会卡顿? - A ...

  2. jmeter动态获取jsessionid

    思想是在一个线程组内添加一个cookie管理器,登录之后,用正则提取到sessionid,该线程组下的操作便可以共享这个session了. 1. 依次新建线程组.cookie管理器.http请求-登录 ...

  3. 失败的尝试,使用继承扩展数组,以及ES6的必要性

    我们都知道直接在原生对象上扩展对象是很不好的.所以prototype这样的库广受非议. 一些库,比如lodash采用了工具包形式的扩展方式,绕开了对象的继承. 由于es6的class的出现,我尝试以A ...

  4. 【个人训练】(POJ1837)Balance

    这几天抓住国庆的黄金时间(因为没有女朋友,天天刷题emmmm 其实还在肝少前还要捞秋刀鱼) ,重点攻克掉几个基本的地方:搜索.dp.图论.这几天的题目应该就是这些范围. 题意 原题的意思大概是这样的, ...

  5. POSTMAN——环境变量

    打开Manage Environment 设置几个自己的环境变量 可以在此看到设置的环境变量 在URL栏填写变量名,这个变量对应着百度的网址 send后可以查看回显 接下来设置全局变量,点开globa ...

  6. ADB常用指令

    adb 命令是adb程序自带的一些命令:adb shell则是调用Android系统的命令,Android系统特有的命令都放在Android设备的/system/bin目录中 MonkeyRunner ...

  7. Tensorflow Estimators

    这篇文章介绍tf.estimator,一个高级TensorFlow API,可以极大简化机器学习编程.Estimators封装了下面几个活动. 训练 评估 预测 出口服务(export for ser ...

  8. Tensorflow编程基础之Mnist手写识别实验+关于cross_entropy的理解

    好久没有静下心来写点东西了,最近好像又回到了高中时候的状态,休息不好,无法全心学习,恶性循环,现在终于调整的好一点了,听着纯音乐突然非常伤感,那些曾经快乐的大学时光啊,突然又慢慢的一下子出现在了眼前, ...

  9. jetty maven插件

    <plugins>   <plugin>    <groupId>org.eclipse.jetty</groupId>    <artifact ...

  10. 不错的PDF开发库

    C++库: 1,PDF类库 PoDoFo   http://podofo.sourceforge.net/  PoDoFo 是一个用来操作 PDF 文件格式的 C++ 类库.它还包含一些小工具用来解析 ...