题目链接http://poj.org/problem?id=1743

题目大意:楼教主の男人八题orz。一篇钢琴谱,每个旋律的值都在1~88以内。琴谱的某段会变调,也就是说某段的数可以加减一个旋律范围的值。问这个谱子内最长不重叠的重复部分大小。

解题思路

网上题解已经泛滥的题。很多细节都被先辈大神总结了。

在当年后缀数组还不是热门的时候,这题确实是神题。

首先对于旋律变调的处理:

比如123,123,ans=3。

变调之后:456,123,ans=0?不ans=3。

所以不能使用旋律的初始值。应该取每个旋律前后的差值,这样就能保证某段无论怎么变调,都和原来一样。

不过这样就变成n-1个旋律,并且ans会-1,可以拿笔算几组看看。

对于取差值后的n-1个旋律,计算SA和LCP。   PS。很多人SA模板都是有问题的,并且推荐自动末尾补0的SA模板,不容易出现问题。

要求不重叠的重复部分大小,这里套用网上被传承N遍的奇葩结论:

将height数组分组,每组内的后缀之间的height都要大于len,如果每组内的后缀之间的最长公共前缀有大于len的而且这两个后缀的SA之差大于len就说明存在长度至少为len的不重复子串。求最长公共前缀就要用到height数组,因为这组中任意两个后缀的公共前缀必定是某些height值中的最小值,而这个值如果最大则一定是这组中height中的最大值。

由于SA数组按字典序来的,二分SA数组长度。如果len符合要求,则先记录。再向右找更大的,否则向左。注意二分的时候ans初始值为0,不然当n=1的时候,等于没有二分就return了一个ans。

#include "cstring"
#include "cstdio"
#include "string"
#include "iostream"
using namespace std;
#define maxn 23000
int n,r[maxn],tmp[maxn];
template <class T>
inline bool read(T &ret)
{
char c;
int sgn;
if(c=getchar(),c==EOF) return ; //EOF
while(c!='-'&&(c<''||c>'')) c=getchar();
sgn=(c=='-')?-:;
ret=(c=='-')?:(c-'');
while(c=getchar(),c>=''&&c<='') ret=ret*+(c-'');
ret*=sgn;
return ;
}
struct Suffix
{
int sa[maxn],rk[maxn],height[maxn];
int t[maxn],t2[maxn],c[maxn],m;
void init() {m=;}
int cmp(int *r,int a,int b,int l) {return r[a]==r[b]&&r[a+l]==r[b+l];}
void build()
{
int i,k,p,*x=t,*y=t2;
r[n++]=;
for (i=; i<m; i++) c[i]=;
for (i=; i<n; i++) c[x[i]=r[i]]++;
for (i=; i<m; i++) c[i]+=c[i-];
for (i=n-; i>=; i--) sa[--c[x[i]]]=i;
for (k=,p=; k<n; k*=,m=p)
{
for (p=,i=n-k; i<n; i++) y[p++]=i;
for (i=; i<n; i++) if (sa[i]>=k) y[p++]=sa[i]-k;
for (i=; i<m; i++) c[i]=;
for (i=; i<n; i++) c[x[y[i]]]++;
for (i=; i<m; i++) c[i]+=c[i-];
for (i=n-; i>=; i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=;
x[sa[]]=;
for (i=; i<n; i++) x[sa[i]]=cmp(y,sa[i-],sa[i],k)?p-:p++;
}
n--;
}
void LCP()
{
int i,j,k=;
for (i=; i<=n; i++) rk[sa[i]]=i;
for (i=; i<n; i++)
{
if (k) k--;
j=sa[rk[i]-];
while (r[i+k]==r[j+k]) k++;
height[rk[i]]=k;
}
}
bool judge(int len)
{
int l=sa[],r=sa[];
for(int i=;i<=n;i++)
{
if(height[i]<len)
{
l=sa[i];r=sa[i];
continue;
}
l=min(l,sa[i]);
r=max(r,sa[i]);
if(r-l>len) return true;
}
return false;
}
int BinarySearch()
{
int l=,r=n,mid,ans=;//注意ans=0,不然当n=1的时候返回的是没赋值的ans
while(l<=r)
{
int mid=l+(r-l)/;
if(judge(mid)) {ans=mid;l=mid+;}
else r=mid-;
}
return ans;
}
};
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out1.txt","w",stdout);
while(read(n)&&n)
{
for(int i=; i<n; i++) read(tmp[i]);
for(int i=; i<n-; i++) {r[i]=tmp[i+]-tmp[i]+;}
Suffix a;
a.init();
a.build();
a.LCP();
int ans=a.BinarySearch();
if(ans<) printf("0\n");
else printf("%d\n",ans+);
}
}
13560509 neopenx 1743 Accepted 840K 407MS C++ 2761B 2014-10-24 10:20:38

POJ 1743 (后缀数组+不重叠最长重复子串)的更多相关文章

  1. POJ 1743 后缀数组不重叠最长重复子串

    #include<stdio.h> #include<string.h> #include<algorithm> #define maxn 30000 using ...

  2. [Poj1743] [后缀数组论文例题] Musical Theme [后缀数组不可重叠最长重复子串]

    利用后缀数组,先对读入整数处理str[i]=str[i+1]-str[i]+90这样可以避免负数,计算Height数组,二分答案,如果某处H<lim则将H数组分开,最终分成若干块,判断每块中是否 ...

  3. [poj 3693]后缀数组+出现次数最多的重复子串

    题目链接:http://poj.org/problem?id=3693 枚举长度L,看长度为L的子串最多能重复出现几次,首先,能出现1次是肯定的,然后看是否能出现两次及以上.由抽屉原理,这个子串出现次 ...

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

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

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

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

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

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

  7. 【poj1743-Musical Theme】不可重叠最长重复子串-后缀数组

    http://poj.org/problem?id=1743 这题是一道后缀数组的经典例题:求不可重叠最长重复子串. 题意: 有N(1 <= N <=20000)个音符的序列来表示一首乐曲 ...

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

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

  9. poj 3261 后缀数组 可重叠的 k 次最长重复子串

    Milk Patterns Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 16430   Accepted: 7252 Ca ...

随机推荐

  1. Java--多线程读取网络图片并保存在本地

    本例用到了多线程.时间函数.网络流.文件读写.正则表达式(在读取html内容response时,最好不要用正则表达式来抓捕html文本内容里的特征,因为服务器返回的多个页面的文本内容不一定使用相同的模 ...

  2. Linux shell判断文件和文件夹是否存在

    shell判断文件,目录是否存在或者具有权限 #!/bin/sh myPath="/var/log/httpd/" myFile="/var /log/httpd/acc ...

  3. div设置边框黑框显示

    style="width:756px; height:68px; border:1px solid #000000;"

  4. ajax:post 400错误

    POST http://localhost:8080/purchase/purchase-apply/update.htm 400 (Bad Request) n.ajaxTransport.k.co ...

  5. android.mk文件里的通配符

    比方你有如下目录,要编译Classes目录和Code目录下所有cpp src |-android.mk |-Classes |-A.cpp |-B.cpp |-....cpp |-Code |-E.c ...

  6. Windows metro app wcf 地址可配置

    在Windows metro app中调用wcf服务可以通过添加 “服务引用”来实现.一旦项目发布则不可修改.这个和桌面开发不一样. 现在我们通过读取文本的方式来读取wcf地址. 1.添加所需引用的w ...

  7. 六间房 繁星 酷我 来疯 秀吧 新浪秀 直播播放器 Live 1.2

    适合用于进行录制的时候 特别说明: 安装 falsh play 19 时 不能正常播放 每个按钮都有提示,不详细说明 下载地址 http://pan.baidu.com/s/1i32ETIt 下载地址 ...

  8. 1.saltstack基础笔记

    环境: master: 节点node1:阿里云:121.42.195.15 centos6.6 minion: 节点node2:腾讯云:182.254.157.19 centos6.6 一.salts ...

  9. DFS:Lake Counting(POJ 2386)

    好吧前几天一直没更新博客,主要是更新博客的确是要耗费一点精力 北大教你数水坑 最近更新博客可能就是一点旧的东西和一些水题,主要是最近对汇编感兴趣了嘻嘻嘻 这一题挺简单的,没什么难度,简单深搜 #inc ...

  10. HDU2084基础DP数塔

    数塔 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submissi ...