hiho121
来源:互联网 发布:淘宝女装网店名字 编辑:程序博客网 时间:2024/06/14 07:36
描述
小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:哈哈,不难嘛,我马上去实现一发!
输入
第一行一个整数 N。1≤N≤100000
接下来有 N 个整数,表示每个音的数字。1≤数字≤1000
输出
一行一个整数,表示答案。
- 样例输入
81 2 3 2 3 2 3 1
- 样例输出
2
<span style="font-family:Arial;font-size:14px;">#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <climits>using namespace std;const int MAXN = 100010;int ch[MAXN], sa[MAXN], tsa[MAXN], cntA[MAXN], cntB[MAXN], Rank[MAXN], A[MAXN], B[MAXN], height[MAXN];int n;void solve(){ for( int i=0 ; i<1001 ; i++ ) cntA[i] = 0; for( int i=1 ; i<=n ; i++ ) cntA[ch[i]]++; for( int i=1 ; i<=1000 ; i++ ) cntA[i] += cntA[i-1]; for( int i=n ; i; i-- ) sa[cntA[ch[i]]--] = i; Rank[sa[1]] = 1; for( int i=2 ; i<=n ; i++ ) { Rank[sa[i]] = Rank[sa[i-1]]; if( ch[sa[i]] != ch[sa[i-1]] ) Rank[sa[i]]++; } for( int l=1 ; l<=n ; l<<=1 ) { for( int i=0 ; i<=n ; i++ ) cntA[i] = cntB[i] = 0; for( int i=1 ; i<=n ; i++ ) { cntA[A[i] = Rank[i]]++; cntB[B[i] = (i+l<=n) ? Rank[i+l] : 0 ]++; } for( int i=1 ; i<=n ; i++ ) cntB[i] += cntB[i-1]; for( int i=n ; i ; i-- ) tsa[cntB[B[i]]--] = i; for( int i=1 ; i<=n ; i++ ) cntA[i] += cntA[i-1]; for( int i=n ; i ; i-- ) sa[cntA[A[tsa[i]]]--] = tsa[i]; Rank[sa[1]] = 1; for( int i=2 ; i<=n ; i++ ) { Rank[sa[i]] = Rank[sa[i-1]]; if( A[sa[i]] != A[sa[i-1]] || B[sa[i]] != B[sa[i-1]] ) Rank[sa[i]]++; } } for( int i=1, j=0 ; i<=n ; i++ ) { if(j) j--; while( ch[i+j] == ch[sa[Rank[i]-1] + j ] ) j++; height[Rank[i]] = j; }}bool check( int k ){ int minsa,maxsa; minsa = maxsa = 0; 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;}int main(){ //freopen( "in.txt", "r", stdin ); cin>>n; for( int i=1 ; i<=n ; i++ ) cin>>ch[i]; solve(); int ans = 0; for( ; ans<= n/2; ans++ ) { if( check(ans) && !check(ans+1) ) break; } cout<<ans<<endl; //cout << "Hello world!" << endl; return 0;}</span>
- hiho121
- [第二步]在NanoPi NEO UbuntuCore下安装homebridge(相关错误解决,希望能帮到同样遇到这些问题的朋友)
- 经典问题三.(环形区间dp) 项链 nyoj 460
- spark-两种运行模式流程yarn-clusert与yarn-client
- 会跳动的心
- 欢迎使用CSDN-markdown编辑器
- hiho121
- java.lang.UnsatisfiedLinkError: Native method not found: com.baidu.platform.comjni.engine.JNIEngine.
- android常用控件ViewPager(二) ViewPager与Fragment
- 汇编语言之寄存器(详细介绍)
- Java回顾之ORM框架
- 雷塞DMC1380的使用:常用编程函数
- [uboot] (第四章)uboot流程——uboot编译流程
- C语言文件概述
- AspectJ 在spring项目中的maven配置