题目链接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. [POJ1050]To the Max

    [POJ1050]To the Max 试题描述 Given a two-dimensional array of positive and negative integers, a sub-rect ...

  2. Java修改数组长度

    java中没有关于修改数组长度的api,在此本人提供了修改数组长度的两个函数:arrayAddLength()和arrayReduceLength().详细见代码.  [java] view plai ...

  3. 每天一个脚本解析day1==》《service xxxxx status》之service脚本解析

    vim    /sbin/service #!/bin/sh . /etc/init.d/functions #读取环境变量. VERSION="$(basename $0) ver. 0. ...

  4. 怎样取出cobbler kopts中设置的参数?

    Is there a way to find out with what parameters did the kernel boot? For example if I specify noexec ...

  5. poj 2709

    http://poj.org/problem?id=2709 题意:就是那个老师需要n瓶颜色的墨水,和1瓶颜色的灰色的墨水,但是灰色的墨水没得卖,只能由三种颜色相同的墨水混合而成,但是3瓶50ML的墨 ...

  6. VIM中的折叠命令

    参考:http://blog.csdn.net/bruce0532/article/details/8497284 za:在折叠与展开间自由转换 zf:创建折叠 示例:zf 3j    #本行及以下3 ...

  7. schedule CCCallfunc CCCallfuncN CCCallfuncND

    schedule(schedule_selector(HelloWorld::step), 1.0f); void HelloWorld::step(float dt) { CCLog("d ...

  8. IE8 不支持html5 placeholder的解决方案

    IE8不支持html5 placeholder的解决方法. /** * jQuery EnPlaceholder plug * version 1.0 2014.07.01戈志刚 * by Frans ...

  9. js判空

    2014年9月3日 11:36:10 转载的: http://blog.sina.com.cn/s/blog_755168af0100vsik.html typeof用法 typeof的运算数未定义, ...

  10. Linux服务器通过rz/sz轻松上传下载文件

    Linux服务器通过命令行远程访问时,上传文件还需要ftp所以不太方便,可以使用rz这个小工具来上传不太大的文件,方法如下: 输入rz,如果提示命令不存在,证明还没有安装,以CentOS为例,安装命令 ...