题目链接:https://cn.vjudge.net/contest/283743#problem/C

题目大意:给你n个数组,然后问你是否有多个“相似”且不重叠的子串的长度大于等于5(两个子串相似当且仅当长度相等且每一位的数字差都相等)。

具体思路:对于相似,我们直接对于当前的输入的和他的上一位相减就可以了,这样差就表示出来了,然后就开始判断时候有相同的子串并且不重叠并且长度>=5就可以了。判断的时候,首先分组,分组的标准是这个组里面的height是不是大于等k,对于每一个组,找出最大的sa差值,然后就判断差值和5的关系就可以了。对于具体的原因,height[i]数组指的是排序之后,排名为i和i-1的最长公共前缀,然后再分组的时候,如果height数组>=k的时候,就直接判断这两个字符串的开头位置就可以了,这个可以通过sa数组实现。

AC代码:

 #include<iostream>
#include<stack>
#include<cstring>
#include<iomanip>
#include<stdio.h>
#include<algorithm>
#include<cmath>
using namespace std;
# define ll long long
# define inf 0x3f3f3f3f
const int maxn = 5e5+;
int cntA[maxn], cntB[maxn], sa[maxn], tsa[maxn], A[maxn], B[maxn], height[maxn];
int Rank[maxn];
int ch[maxn];
int sto[maxn];
ll n;
//sa[i]代表第i小的后缀位置,Rank[i]代表第i位置的后缀,排名第几小
// height[i]代表排名第i个字符串和第i-1个字符串的相同前缀有多少个
void cal()
{
for(int i = ; i < ; i++)
cntA[i] = ;
// cout<<1<<endl;
// cout<<n<<endl;
for(int i = ; i <= n; i++){
//cout<<ch[i-1]<<endl;
cntA[ch[i-]]++;
}
// cout<<1<<endl;
for(int i = ; i < ; i++)
cntA[i] += cntA[i-];
for(int i = n; i; i--)
sa[cntA[ch[i-]]--] = i;
Rank[sa[]] = ;
for(int i = ; i <= n; i++)
{
Rank[sa[i]] = Rank[sa[i-]];
if(ch[sa[i]-] != ch[sa[i-]-])
Rank[sa[i]]++;
}
for(int l = ; Rank[sa[n]] < n; l <<= )
{
memset(cntA, , sizeof(cntA));
memset(cntB, , sizeof(cntB));
for(int i = ; i <= n; i++)
{
cntA[A[i] = Rank[i]]++;
cntB[B[i] = (i+l <= n)?Rank[i+l]:]++;
}
for(int i = ; i <= n; i++)
cntB[i] += cntB[i-];
for(int i = n; i; i--)
tsa[cntB[B[i]]--] = i;
for(int i = ; i <= n; i++)
cntA[i] += cntA[i-];
for(int i = n; i; i--)
sa[cntA[A[tsa[i]]]--] = tsa[i];
Rank[sa[]]=;
for(int i = ; i <= n; i++)
{
Rank[sa[i]] = Rank[sa[i-]];
if(A[sa[i]] != A[sa[i-]] || B[sa[i]] != B[sa[i-]])
Rank[sa[i]]++;
}
}
for(int i = , j = ; i <= n; i++)
{
if(j)
j--;
while(ch[i+j-] == ch[sa[Rank[i]-] + j - ])
j++;
height[Rank[i]] = j;
}
}
bool judge(int t)
{
int mx=-inf,mm=inf;
for(int i=; i<=n; i++)
{
if(height[i]>=t)
{
mm=min(mm,min(sa[i],sa[i-]));
mx=max(mx,max(sa[i],sa[i-]));
if(mx-mm>t)
return true;
}
else
{
mm=inf;
mx=-inf;
}
}
return false;
}
int main()
{
// int n;
while(scanf("%d",&n)&&n)
{
for(int i=; i<n; i++)
{
scanf("%d",&sto[i]);
}
for(int i=; i<n; i++)
{
ch[i]=sto[i+]-sto[i]+;
}
n--;
cal();
int ans=-;
int l=,r=1e8;
while(l<=r)
{
int mid=(l+r)>>;
// cout<<l<<" "<<r<<endl;
if(judge(mid))
{
ans=mid;
l=mid+;
// cout<<ans<<endl;
}
else
{
r=mid-;
}
}
if(ans>=)
printf("%d\n",ans+);
else
{
printf("0\n");
}
}
return ;
}

C - Musical Theme (后缀数组)的更多相关文章

  1. POJ1743 Musical Theme [后缀数组]

    Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 27539   Accepted: 9290 De ...

  2. POJ 1743 Musical Theme 后缀数组 最长重复不相交子串

    Musical ThemeTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://poj.org/problem?id=1743 Description ...

  3. POJ1743 Musical Theme [后缀数组+分组/并查集]

    Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 27539   Accepted: 9290 De ...

  4. poj 1743 Musical Theme (后缀数组+二分法)

    Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 16162   Accepted: 5577 De ...

  5. POJ1743 Musical Theme —— 后缀数组 重复出现且不重叠的最长子串

    题目链接:https://vjudge.net/problem/POJ-1743 Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Tot ...

  6. Poj 1743 Musical Theme(后缀数组+二分答案)

    Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 28435 Accepted: 9604 Descri ...

  7. [poj 1743] Musical Theme 后缀数组 or hash

    Musical Theme 题意 给出n个1-88组成的音符,让找出一个最长的连续子序列,满足以下条件: 长度大于5 不重叠的出现两次(这里的出现可以经过变调,即这个序列的每个数字全都加上一个整数x) ...

  8. Poj 1743 Musical Theme (后缀数组+二分)

    题目链接: Poj  1743 Musical Theme 题目描述: 给出一串数字(数字区间在[1,88]),要在这串数字中找出一个主题,满足: 1:主题长度大于等于5. 2:主题在文本串中重复出现 ...

  9. POJ 1743 Musical Theme ——后缀数组

    [题目分析] 其实找最长的不重叠字串是很容易的,后缀数组+二分可以在nlogn的时间内解决. 但是转调是个棘手的事情. 其实只需要o(* ̄▽ ̄*)ブ差分就可以了. 背板题. [代码] #include ...

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

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

随机推荐

  1. python 模块之-hashlib

    python 模块hashlib import hashlib m=hashlib.md5()         # 生成MD5加密对象 m.update('jiami-string'.encode(' ...

  2. day12 max min zip 用法

    max min ,查看最大值,最小值 基础玩法 l = [1,2,3,4,5] print(max(l)) print(min(l)) 高端玩法 默认字典的取值是key的比较 age_dic={'al ...

  3. MT【216】韦达定理

    设$n$为正整数,$a_1,a_2,\cdots,a_n;b_1,b_2,\cdots,b_n;A,B$都是正数, 满足$a_i\le b_i,a_i\le A,i=1,2,\cdots,n$ 且$\ ...

  4. Codeforces Round #487 (Div. 2) E. A Trance of Nightfall (矩阵优化)

    题意 有一个平面 , 给你 \(n\) 个点构成一个点集 \(S\) , 一开始可以选择一个平面上任意点 \(P\) . 存在一种操作 : 1 选择一条至少 通过 \(S\) 中任意两个点以及 \(P ...

  5. 【BZOJ2229】[ZJOI2011]最小割(网络流,最小割树)

    [BZOJ2229][ZJOI2011]最小割(网络流,最小割树) 题面 BZOJ 洛谷 题解 戳这里 那么实现过程就是任选两点跑最小割更新答案,然后把点集划分为和\(S\)联通以及与\(T\)联通. ...

  6. CodeForces 464E The Classic Problem | 呆克斯歘 主席树维护高精度

    题意描述 有一个\(n\)点\(m\)边的无向图,第\(i\)条边的边权是\(2^{a_i}\).求点\(s\)到点\(t\)的最短路长度(对\(10^9 + 7\)取模). 题解 思路很简单--用主 ...

  7. HGOI 20190217 题解

    /* for me,开训第一天 /beacuse 文化课太差被抓去补文化课了... 看一眼题 : AK局? 但是,Wa on test #10 in problem C 290! (就差那么一咪咪) ...

  8. LoadRunner断言:正确结果有多种情况

    用过lr的都知道,我们可以用web_reg_find这个注册函数判断某个请求的返回中是否有我们要找的内容. 但是,如果正常的情况有多种,该如何断言呢? 设置多个检查点 把每个检查点获取到的结果数量相加 ...

  9. luogu3380/bzoj3196 二逼平衡树 (树状数组套权值线段树)

    带修改区间K大值 这题有很多做法,我的做法是树状数组套权值线段树,修改查询的时候都是按着树状数组的规则找出那log(n)个线段树根,然后一起往下做 时空都是$O(nlog^2n)$的(如果离散化了的话 ...

  10. Java NIO -- 直接缓冲区与非直接缓冲区

    直接缓冲区与非直接缓冲区: 非直接缓冲区:通过 allocate() 方法分配缓冲区,将缓冲区建立在 JVM 的内存中直接缓冲区:通过 allocateDirect() 方法分配直接缓冲区,将缓冲区建 ...