题意:求最长不可重叠的相同差值子串的长度

这道题算是拖了好几个月,现在花了点时间应该搞懂了不少,尝试分析一下

我们首先来解决一个退化的版本,求最长不可重叠的相同子串(差值为0)

比如\(aabaabaa\), 那么所求的子串有\(aab,aba,baa\)三个

如何求?不妨枚举.枚举是否有长度为\(k\)的最长不可重叠相同子串

可是后缀数组中并不能直接表示出子串,只能间接地用后缀来表示

长度为\(k\)的相同子串\(=>\)最大公共前缀长度为\(k\)的子串\(=>\)最大公共前缀长度大于等于\(k\)的后缀(注意非充要)

而我们所求的就是一个\(lcp\),我们应该分组,每一组内的各个后缀的\(lcp\)都大于等于\(k\),由\(lcp\)定义可转化为组内按\(sa\)排序\(height\)不得小于\(k\)

按照这个规则我们来看下上面的实例如何分组,这是枚举\(k=3\)时的情况

index=8 height[1]=0 \(a\)

index=7 height[2]=1 \(aa\)

index=4 height[3]=2 \(aabaa\)

index=1 height[4]=5 \(aabaabaa\)

index=5 height[5]=1 \(abaa\)

index=2 height[6]=4 \(abaabaa\)

index=6 height[7]=0 \(baa\)

index=3 height[8]=3 \(baabaa\)

我们注意到按照这样排序是没办法知道两个子串是否重叠,所以需要记录\(index\)

其中\(index\)是指该后缀首字符在字符串中的位置(1为首),也就是\(sa[i]\)

那么我们现在就有办法去搞了,因为每一组都保证了\(lcp>=k\),也就是如果重叠也算的话,每一组都是合法的分组(主要组内后缀个数大于1)

现在因为只有不可重叠才是合法条件所以需要剔除非法的后缀,既然有了\(sa\)值那就好办,如果组内任意两个后缀的\(index\)为\(i,j\),那就需要\(i_{max}-j_{min}>=k\),表示该组至少有一对符合条件

至此,枚举\(k=3\)的情况为真,得到的分组按顺序恰有\(aab,aba,baa\)三个,其他情况依次类推二分下去就好

现在再来看原来的问题:求最长相同的差值的不可重叠子串,输出该长度

既然要相同的差值,我们把原串\(n\)个字符(值)转化为\(n-1\)个值的差分数组

同样枚举最长的相同值的不可重叠子串,如果能枚举出最大的\(k\)是成立的,那答案还原回来就是\(k+1\)

但是,需要注意的是对于\(index\),应该要满足\(i_{max}-j_{min}>k\),因为差分数组是必须要留出"空隙"的,否则遇到临界情况就是两个不可重叠子串恰好相连,而这个是差分子串,还原回来就是中间的值恰好被两个原串重复选取了,这也是条件轻微更改的原因

不过这道题的数据应该是随机生成的,即使不改也会AC

楼教主的题真的好劲啊

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<map>
#define rep(i,j,k) for(register int i=j;i<=k;i++)
#define rrep(i,j,k) for(register int i=j;i>=k;i--)
#define erep(i,u) for(register int i=head[u];~i;i=nxt[i])
#define iin(a) scanf("%d",&a)
#define lin(a) scanf("%lld",&a)
#define din(a) scanf("%lf",&a)
#define s0(a) scanf("%s",a)
#define s1(a) scanf("%s",a+1)
#define print(a) printf("%lld",(ll)a)
#define enter putchar('\n')
#define blank putchar(' ')
#define println(a) printf("%lld\n",(ll)a)
#define IOS ios::sync_with_stdio(0)
using namespace std;
const int maxn = 1e6+11;
const int oo = 0x3f3f3f3f;
const double eps = 1e-7;
typedef long long ll;
ll read(){
ll x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int str[maxn],n;
struct SA{
int Rank[maxn],sa[maxn],tsa[maxn],A[maxn],B[maxn];
int cntA[maxn],cntB[maxn];
int height[maxn],best[maxn][30],n;//height[i]:第sa[i]与sa[i-1]的cp
void get(int nn){
n=nn;
rep(i,0,666) cntA[i]=0;
rep(i,1,n) cntA[str[i]]++;
rep(i,1,666) cntA[i]+=cntA[i-1];
rrep(i,n,1) sa[cntA[str[i]]--]=i;
Rank[sa[1]]=1;
rep(i,2,n){
if(str[sa[i]]==str[sa[i-1]]){
Rank[sa[i]]=Rank[sa[i-1]];
}else{
Rank[sa[i]]=1+Rank[sa[i-1]];
}
}
for(int l=1;Rank[sa[n]]<n;l<<=1){
rep(i,1,n) cntA[i]=cntB[i]=0;
rep(i,1,n) cntA[A[i]=Rank[i]]++;
rep(i,1,n) cntB[B[i]=(i+l<=n?Rank[i+l]:0)]++;
rep(i,1,n) cntA[i]+=cntA[i-1],cntB[i]+=cntB[i-1];
rrep(i,n,1) tsa[cntB[B[i]]--]=i;
rrep(i,n,1) sa[cntA[A[tsa[i]]]--]=tsa[i];
Rank[sa[1]]=1;
rep(i,2,n){
bool flag=A[sa[i]]==A[sa[i-1]]&&B[sa[i]]==B[sa[i-1]];
flag=!flag;
Rank[sa[i]]=Rank[sa[i-1]]+flag;
}
}
}
void ht(){
int j=0;
rep(i,1,n){
if(j) j--;
while(str[i+j]==str[sa[Rank[i]-1]+j]) j++;
height[Rank[i]]=j;
}
}
void rmq(){
rep(i,1,n) best[i][0]=height[i];
for(int i=1;(1<<i)<=n;i++){
for(int j=1;j+(1<<i)-1<=n;j++){
best[j][i]=min(best[j][i-1],best[j+(1<<(i-1))][i-1]);
}
}
}
int query(int l,int r){
if(l==r)return -oo;
if(l>r)swap(l,r);
l++;
int k=log2(r-l+1);
return min(best[l][k],best[r-(1<<k)+1][k]);
}
}sa; bool check(int k){
int mx=-oo,mn=oo;
for(int i=2;i<=n;i++){
if(sa.height[i]>=k){
mx=max(mx,max(sa.sa[i],sa.sa[i-1]));
mn=min(mn,min(sa.sa[i],sa.sa[i-1]));
if(mx-mn>k)return 1;
}else{
mx=-oo;mn=oo;
}
}
return 0;
}
int main(){
while(scanf("%d",&n),n){
rep(i,1,n) str[i]=read();
if(n<5){
printf("0\n");
continue;
}
rep(i,1,n) str[i]=str[i+1]-str[i]+100;
str[n]=0;n--;
sa.get(n);
sa.ht();
int l=0,r=n,mid,ans=0;
while(l<=r){
mid=(l+r)>>1;
if(check(mid)) l=mid+1,ans=mid;
else r=mid-1;
}
if(ans+1>=5) println((ans+1));
else println(0);
}
return 0;
}

[八分之一的男人]POJ - 1743 后缀数组 height分组 带详解的更多相关文章

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

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

  2. POJ 1743 后缀数组

    题目链接:http://poj.org/problem?id=1743 题意:给定一个钢琴的音普序列[值的范围是(1~88)],现在要求找到一个子序列满足 1,长度至少为5 2,序列可以转调,即存在两 ...

  3. poj 1743 后缀数组 求最长不重叠重复子串

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

  4. Musical Theme POJ - 1743 后缀数组

    A musical melody is represented as a sequence of N (1<=N<=20000)notes that are integers in the ...

  5. 后缀数组 DC3构造法 —— 详解

    学习了后缀数组,顺便把DC3算法也看了一下,传说中可以O(n)复杂度求出文本串的height,先比较一下倍增算法和DC3算法好辣. DC3 倍增法 时间复杂度 O(n)(但是常数很大)   O(nlo ...

  6. acdream 1430 SETI 后缀数组+height分组

    这题昨天比赛的时候逗了,后缀想不出来,由于n^2的T了,就没往后缀数组想--并且之后解题的人又说用二分套二分来做.然后就更不会了-- 刚才看了题解,唉--原来题讲解n^2的也能够过,然后就--这样了! ...

  7. poj 1743 后缀数组 最长不重叠子串

    Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 30941   Accepted: 10336 D ...

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

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

  9. POJ 1743 (后缀数组 二分) Musical Theme

    看来对height数组进行分段确实是个比较常用的技巧. 题意: 一个主题是可以变调的,也就是如果这个主题所有数字加上或者减少相同的数值,可以看做是相同的主题. 一个主题在原串中至少要出现两次,而且一定 ...

随机推荐

  1. 基于unittest测试框架的扩展

    1 unittest介绍 Unittest,Python自带的单元测试框架,PyUnit类包含TestResult,TestCase, TestSuite,TextTestResult,TextTes ...

  2. 字符串的查找删除---C++中string.find()函数与string::npos

    给定一个短字符串(不含空格),再给定若干字符串,在这些字符串中删除所含有的短字符串 输入: 输入只有一组数据 输入一个短字符串(不含空格),再输入若干字符串直到文件结束为止 输出: 删除输入的短字符串 ...

  3. POJ2442 Sequence(堆的骚操作)

    Description Given m sequences, each contains n non-negative integer. Now we may select one number fr ...

  4. python之numpy文件操作

    目录 numpy 中的文件操作总结 CVS文件 多维数据的存取 numpy 的便捷文件存取 numpy 中的文件操作总结 CVS文件 CSV (Comma‐Separated Value,逗号分隔值) ...

  5. Sublime Text 2插件推荐

    必装Package Control 使用Ctrl+`快捷键或者通过View->Show Console菜单打开命令行,粘贴如下代码: import urllib2,os; pf='Package ...

  6. Linux 命令之chmod

    立贴今日吉,不断更新,欢迎斧正,支持为感! 1. chmod --权限控制 chmod [-cfvR] [--help] [--version] mode file... 说明 : Linux/Uni ...

  7. 百度云BDCloudVideoView播放器的初体验

    今天试用了一下百度云BDCloudVideoView,记录下遇到的坑. 前面一切还好,按照他的要求各种导入,然后开始码代码,起实就是抄例子.然后各种坑开始了 下面这个你看名称能知道它是个啥吗? mVi ...

  8. Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'blog.t_blog.addTime' which is not functi

    sql报错: Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Expression #1 of SELECT ...

  9. python3好用的requests库

    python3好用的requests库 requests是什么? requests是基于urllib编写的http库,支持python3,比urllib更好用,更简单.之前使用python写一些htt ...

  10. IIS只允许某些IP访问

    1. 2. 3.访问时提示 4.设置允许访问的IP 5.指定的IP访问时没问题了,而其他的IP不允许访问