描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为长度为 N 的数构成的数列。小Hi在练习过很多曲子以后发现很多作品自身包含一样的旋律。

旋律可以表示为一段连续的数列,相似的旋律在原数列不可重叠,比如在1 2 3 2 3 2 1 中 2 3 2 出现了一次,2 3 出现了两次,小Hi想知道一段旋律中出现次数至少为两次的旋律最长是多少?

解题方法提示

×
解题方法提示
小Ho:这一次的问题该如何解决呢?

小Hi:嗯,这次的问题被称为最长不可重叠重复子串问题。

小Ho:和上次的问题好像啊,但是这一次是不可以重叠的,直接使用上次的算法似乎行不通喔。

小Hi:是的。问题的关键就出在直接用 height 数组不能保证两后缀不重叠,我们得换个思路考虑。

小Ho:可不可以二分答案,转化成判定问题呢?

小Hi:是个好思路,这的确是可行的。我们先二分一个k,表示我们假设串中存在长度为k的不可重叠重复子串。

小Ho:嗯,就是这个意思。

小Hi:存在长度为k的不可重复子串等价于存在两个后缀有长度为k的公共前缀(这里没有要求不重叠)。我们检查 height 数组中有哪些值 ≥ k。并且如果有连续的height值 ≥ k,就把对应的后缀分在同一组。这样就保证了该组中所有后缀两两之间的最长公共前缀都是不小于k的。

我们以样例为例,看一下k=2和k=3的情况。

x i height k=2 k=3
1 8 0
1 2 3 2 3 2 3 1 1 1
2 3 1 6 0
2 3 2 3 1 4 2 >=2
2 3 2 3 2 3 1 2 4 >=2 >=3
3 1 7 0
3 2 3 1 5 1
3 2 3 2 3 1 3 3 >=2 >=3
可以看出,当k=2时,"231"和"23231"的公共前缀大于等于k,"23231"和"2323231"的公共前缀也大于等k,所以这3个排名连续的后缀会被分到一组。同理"3231"和"323231"也会被分到一组。

对于k=3,"23231"和"2323231"分到一组,"3131"和"323231"分到一组。

小Ho:我知道了!

小Hi:对,没错!下面我们要看看能不能找出不重叠的重复子串。对于每一组,我们检查这些后缀对应的sa值(也就是后缀起点在原串中的位置i)。如果max{sa} - min{sa} >= k,那么就说明我们能找出一组不重叠的重复子串。

例如对于k=3,"23231"和"2323231"的sa值是4和2,"3131"和"323231"这一组的sa值是5和3,差值都不满足大于等于3,所以找不出不重叠的。

对于k=2,第一组max{sa}-min{sa}=6-2=4满足大于等于2,所以能找出不重叠的。

我们给出如下c++代码:

bool check(int K)
{
for(int i=1;i<=n;i++)
if(height[i]< K)
{
minsa=sa[i];
maxsa=sa[i];
}
else
{
minsa=min(minsa,sa[i]);
maxsa=max(maxsa,sa[i]);
if(maxsa-minsa>=K)return true;
}
return false;
}
小Ho:哈哈,不难嘛,我马上去实现一发!

Close
输入
第一行一个整数 N。1≤N≤100000

接下来有 N 个整数,表示每个音的数字。1≤数字≤1000

输出
一行一个整数,表示答案。

Sample Input
8
1 2 3 2 3 2 3 1
Sample Output
2

数据很水,把上面给的函数放进二分就好了,如果max和min的sa值相差大于k的话就说明存在大于等于k的串

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN =(int)1e6+10;
int wa[MAXN],wb[MAXN],wv[MAXN],we[MAXN],rk[MAXN];
int cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}
void build_sa(int *r,int *sa,int n,int m){int i,j,p,*x=wa,*y=wb,*t;for(i=0;i<m;i++)we[i]=0;for(i=0;i<n;i++)we[x[i]=r[i]]++;for(i=1;i<m;i++)we[i]+=we[i-1];for(i=n-1;i>=0;i--)sa[--we[x[i]]]=i;for(j=1,p=1;p<n;j*=2,m=p){for(p=0,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<n;i++)wv[i]=x[y[i]];for(i=0;i<m;i++)we[i]=0;for(i=0;i<n;i++)we[wv[i]]++;for(i=1;i<m;i++)we[i]+=we[i-1];for(i=n-1;i>=0;i--)sa[--we[wv[i]]]=y[i];for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;}
}
int height[MAXN];
void calheight(int *r,int *sa,int n){int i,j,k=0;for(i=1;i<=n;i++)rk[sa[i]]=i;for(i=0;i<n;height[rk[i++]]=k){for(k?k--:0,j=sa[rk[i]-1];r[i+k]==r[j+k];k++);}
}
int sa[MAXN],a[MAXN];
//sa是从1-n,开始的值是0,rk是从0- n-1,开始的值是1
int n,k;
bool check(int K)
{int minsa=1e5,maxsa=1e5;for(int i=0;i<=n;i++){if(height[i]< K){minsa=sa[i];maxsa=sa[i];}else{minsa=min(minsa,sa[i]);maxsa=max(maxsa,sa[i]);if(maxsa-minsa>=K)return true;}}return false;
}
int main()
{scanf("%d",&n);for(int i=0;i<n;i++)scanf("%d",&a[i]);build_sa(a,sa,n+1,2000);calheight(a,sa,n);int low=0,high=1e5,mid,ans;while(high>=low){mid=low+high>>1;if(check(mid))ans=mid,low=mid+1;elsehigh=mid-1;}printf("%d\n",ans);return 0;
}

I - 后缀数组二·重复旋律2 HihoCoder - 1407相关推荐

  1. #1407 : 后缀数组二·重复旋律2 (不可重叠最长重复子串问题)

    题目链接 思路 求不可重叠最长重复子串,也可以利用height[i]height[i]height[i]. 二分枚举答案KKK 当height[i]≥Kheight[i] \ge Kheight[i] ...

  2. hiho一下120周 后缀数组一·重复旋律

    后缀数组一·重复旋律 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成的数列. 小Hi ...

  3. hiho一下第128周 后缀自动机二·重复旋律5

    #1445 : 后缀自动机二·重复旋律5 时间限制:10000ms 单点时限:2000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数 ...

  4. HihoCoder - 1445 后缀自动机二·重复旋律5(后缀自动机)

    题目链接:点击查看 题目大意:给出一个字符串 s ,求 s 中本质不同的子串的数量 题目分析:因为 s 的长度给到了 1e6 ,用后缀数组可能会超时,所以最好的方法肯定是用后缀自动机来做,因为每个节点 ...

  5. hihoCoder #1445 : 后缀自动机二·重复旋律5

    描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi想知道一部作品中出现了多少不同的旋律? 输入 共一行,包含一个由小写字母构成的字符串.字符串长度不 ...

  6. #1419 : 后缀数组四·重复旋律4 (重复次数最多的连续字串)

    题目链接 思路 如何求一个串中的最大重复次数? 枚举循环节的大小,判断它是否合法. 如何快速判断循环节合法? LCP(LCP(LCP(原串, 原串−-−循环节)))是否完全匹配. 如何快速求串AAA和 ...

  7. #1415 : 后缀数组三·重复旋律3 (最长公共子串)

    思路 将两个字符串合成一个字符串,中间加上一个"#".然后求height[i]height[i]height[i]. 最长公共子串如果存在,必定是相邻的height[i]heigh ...

  8. #1403 : 后缀数组一·重复旋律 (可重叠最长重复K次子串问题)

    题目链接 思路 K=2K = 2K=2时就是求height[i]height[i]height[i]的最大值. K≠2K =\not 2K≠​2时就是连续K−1K-1K−1个height[i]he ...

  9. hihocoder 1465 : 后缀自动机五·重复旋律8(后缀自动机+最长公共子串)

    1465 : 后缀自动机五·重复旋律8 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的 ...

最新文章

  1. 模拟实现: strstr strcpy strlen strcat strcmp memcpy memmove
  2. python datasets_python基础之sklearn.datasets
  3. Java 基本数据类型 sizeof 功能
  4. TypeError之: unsupported operand type(s) for +: 'dict_values' and 'dict_values
  5. python编程学习做什么-什么样的人要学点python编程?请你对号入座
  6. 【MySQL】RPM包安装
  7. Enterprise Library Policy Injection Application Block 之一: PIAB Overview
  8. 2022年电工(技师)特种作业证考试题库及在线模拟考试
  9. RouterOS PPTP和L2TP的配置
  10. php微信网页授权获取用户基本信息,微信网页授权获取用户基本信息
  11. vue-router 详解
  12. safari 浏览器版本升级后提示“此网页出现问题,已重新载入网页” 解决办法
  13. pandas结合matplotlib将excel数据可视化
  14. 安防4G摄像头视频流媒体服务器EasyNVR关于视频集成自我展示web端嵌入视频广场的流程
  15. three.js中坐标系转换以及camera的position、lookAt与up属性理解
  16. Mac Tomcat安装 localhost 拒绝了我们的连接请求
  17. STM32开发笔记113:ADS1258驱动设计——读取温度值
  18. Chrome Custom Tabs最佳实践
  19. 基于C#开发的《彩色连珠》小游戏
  20. 807-C++多继承下,派生类对象有几张虚函数表?

热门文章

  1. 最小二乘法拟合圆公式推导及其实现
  2. 常见的分布式数据库有哪些
  3. 28335的启动步骤介绍
  4. 脑壳疼,好好的系统,为什么要分库分表?
  5. 魔兽世界无限从服务器断开连接,wow无法连接服务器(魔兽世界7.0已从服务器断开51900319解决方法介绍)...
  6. js引用类型之RegExp类型-new RegExp()
  7. 斐波那契数列的前N项和
  8. 目标检测:各种网络结构对比
  9. 计算机在会计中的应用英语论文,计算机在会计中应用期刊文章参考文献 计算机在会计中应用英语参考文献哪里找...
  10. 二重调度(一):什么是二重调度?