BZOJ3230 相似子串[后缀数组+二分+st表]
给一个串,查询排名i和j的子串longest common suffix和longest common prefix
思路其实还是蛮好想的,就是码起来有点恶心。可以发现后缀拍完序之后的子串可以根据sa自前而后的顺序标子串排名,和统计不同字串那里差不多,自lcp后的是新子串,开始标记排名。实际操作时在每个后缀上标这一后缀开始第一个新子串排名,可证是单调增的,然后查询就二分查出子串开始的后缀也就是位置啦,然后用st表维护子串(所在后缀的)lcp即可。lcs的话就把串反转一下做个排序同理st表维护RMQ。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=+,Log=;
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline void read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=(x<<)+(x<<)+(c^),c=getchar();f?x-=x:;
}
char s[][N];
int po[N],n,q,a,b,h1,r1,h2,r2,l1,l2;
ll q1,q2; int cnt[][N],h[][N],sa[][N],rk[][N],y[][N],m,p;
inline void suffix_sort(int l){ m=,p=;
for(register int i=;i<=n;++i)++cnt[l][rk[l][i]=s[l][i]];
for(register int i=;i<=m;++i)cnt[l][i]+=cnt[l][i-];
for(register int i=n;i;--i)sa[l][cnt[l][rk[l][i]]--]=i;
for(register int k=;k<n;k<<=,p=){
for(register int i=n-k+;i<=n;++i)y[l][++p]=i;
for(register int i=;i<=n;++i)if(sa[l][i]>k)y[l][++p]=sa[l][i]-k;
for(register int i=;i<=m;++i)cnt[l][i]=;
for(register int i=;i<=n;++i)++cnt[l][rk[l][y[l][i]]];
for(register int i=;i<=m;++i)cnt[l][i]+=cnt[l][i-];
for(register int i=n;i;--i)sa[l][cnt[l][rk[l][y[l][i]]]--]=y[l][i];
swap(rk,y);rk[l][sa[l][]]=p=;
for(register int i=;i<=n;++i)rk[l][sa[l][i]]=y[l][sa[l][i-]]==y[l][sa[l][i]]&&y[l][sa[l][i-]+k]==y[l][sa[l][i]+k]?p:++p;
if(p==n)break;m=p;
}p=;
for(register int i=;i<=n;h[l][rk[l][i]]=p,p?--p:,++i)while(s[l][i+p]==s[l][sa[l][rk[l][i]-]+p]&&++p);
} ll rank[N],tot=;
inline void mark(){for(register int i=;i<=n;++i)rank[i]=tot,tot+=n-sa[][i]+-h[][i];--tot;}
struct st_table{
int lcp[N][Log];
inline void build(int l){
for(register int i=;i<=n;++i)lcp[i][]=h[l][i];
for(register int k=;k<=po[n];++k)for(register int i=;i<=n+-(<<k);++i)
lcp[i][k]=_min(lcp[i][k-],lcp[i+(<<(k-))][k-]);
}
inline int RMQ(int l,int r){return _min(lcp[l][po[r-l+]],lcp[r-(<<po[r-l+])+][po[r-l+]]);}
}pos,neg;//positive,negative int main(){//freopen("tmp.txt","r",stdin);
read(n),read(q),scanf("%s",s[]+);
for(register int i=;i<=n;++i)po[i]=(i-)==(<<(po[i-]+))?po[i-]+:po[i-];
for(register int i=;i<=n;++i)s[][i]=s[][n-i+];
suffix_sort(),suffix_sort(),mark();
pos.build(),neg.build();
// for(register int i=1;i<=n;++i)cerr<<s[1][i];puts("");
// for(register int i=1;i<=n;++i)cerr<<i<<" "<<rk[1][i]<<" "<<sa[1][i]<<endl;
for(register int i=;i<=q;++i){
read(q1),read(q2);
if(q1>tot||q2>tot){printf("-1\n");continue;}
h1=upper_bound(rank+,rank+n+,q1)-rank-,h2=upper_bound(rank+,rank+n+,q2)-rank-;
l1=sa[][h1],l2=sa[][h2],r1=l1+h[][h1]+q1-rank[h1],r2=l2+h[][h2]+q2-rank[h2];
if(h1==h2)a=_min(r1,r2)-l1+;
else{
if(h1>h2)h1^=h2^=h1^=h2;
a=pos.RMQ(h1+,h2);if((a>r1-l1+)||(a>r2-l2+))a=_min(r1-l1+,r2-l2+);
}//get a.
h1=rk[][n-r1+],h2=rk[][n-r2+];//cerr<<l1<<" "<<r1<<" "<<l2<<" "<<r2<<" "<<h1<<" "<<h2<<endl;
if(h1==h2)b=r1-_max(l1,l2)+;
else{
if(h1>h2)h1^=h2^=h1^=h2;
b=neg.RMQ(h1+,h2);if((b>r1-l1+)||(b>r2-l2+))b=_min(r1-l1+,r2-l2+);
}//get b.
printf("%lld\n",1ll*a*a+1ll*b*b);
}
return ;
}
BZOJ3230 相似子串[后缀数组+二分+st表]的更多相关文章
- BZOJ 3230 相似子串 | 后缀数组 二分 ST表
BZOJ 3230 相似子串 题面 题解 首先我们要知道询问的两个子串的位置. 先正常跑一遍后缀数组并求出height数组. 对于每一个后缀suffix(i),考虑以i开头的子串有多少是之前没有出现过 ...
- [BZOJ4310] 跳蚤 - 后缀数组,二分,ST表
[BZOJ4310] 跳蚤 Description 首先,他会把串分成不超过 \(k\) 个子串,然后对于每个子串 \(S\) ,他会从 \(S\) 的所有子串中选择字典序最大的那一个,并在选出来的 ...
- bzoj 3230 相似子串 —— 后缀数组+二分
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3230 先算出每个后缀贡献子串的区间: 然后前缀LCP直接查询,后缀LCP二分长度,查询即可: ...
- [BZOJ3230]相似子串(后缀数组)
显然可以通过后缀数组快速找到询问的两个串分别是什么,然后正反各建一个后缀数组来求两个串的LCP和LCS即可. #include<cstdio> #include<cstring> ...
- 【BZOJ3230】相似子串 后缀数组+二分+RMQ
[BZOJ3230]相似子串 Description Input 输入第1行,包含3个整数N,Q.Q代表询问组数.第2行是字符串S.接下来Q行,每行两个整数i和j.(1≤i≤j). Output 输出 ...
- UOJ #219 BZOJ 4650 luogu P1117 [NOI2016]优秀的拆分 (后缀数组、ST表)
连NOI Day1T1都不会做...看了题解都写不出来还要抄Claris的代码.. 题目链接: (luogu)https://www.luogu.org/problemnew/show/P1117 ( ...
- [BZOJ3277/BZOJ3473] 串 - 后缀数组,二分,双指针,ST表,均摊分析
[BZOJ3277] 串 Description 现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). Solution 首先将所有串连 ...
- BZOJ4556:[TJOI\HEOI2016]字符串(后缀数组,主席树,二分,ST表)
Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱 ...
- BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )
二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) -------------------------------------------------- ...
随机推荐
- rootkit基础
应用程序总是离不开系统内核所提供的服务,比如它要使用内存的时候,只要跟操作系统申请就行了,而不用自己操心哪里有空闲的内存空间等问题,实际上,这些问题是由操作系统的内核来代劳的.站在黑客的角度讲,如果能 ...
- 一、Silverlight中使用MVVM(一)——基础
如果你不知道MVVM模式,我建议你先了解一下MVVM模式,至少要知道实现该模式的意图是什么. 那么我主要通过我认为是已经算是比较简单的例子进行讲解这个模式,当然后面我们会在这个例子的基础上一步一步的进 ...
- mnesia的脏写和事物写的测试
在之前的文章中,测试了脏读和事物读之间性能差别,下面测试下脏写和事物写之间的性能差别: 代码如下: -module(mnesia_text). -compile(export_all). -recor ...
- React系列之--props属性
版权声明:本文为博主原创文章,未经博主允许不得转载. PS:转载请注明出处作者:TigerChain地址:http://www.jianshu.com/p/fa81cebac3ef本文出自TigerC ...
- 多媒体开发之---h264中 的RTP PAYLOAD 格式
H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) NALU 头由一个字节组成, 它的语法如下: +---------------+ |0|1|2|3|4|5|6|7 ...
- win7激活附带激活软件
链接: https://pan.baidu.com/s/1i46yoHR 密码: 7k6y
- Project Euler:Problem 41 Pandigital prime
We shall say that an n-digit number is pandigital if it makes use of all the digits 1 to n exactly o ...
- Intellij IDEA创建的Web项目配置Tomcat并启动Maven项目(转)
大部分是直接上图哦. 点击如图所示的地方,进行添加Tomcat配置页面 弹出页面后,按照如图顺序找到,点击+号 tomcat Service -> Local 注意,这里不要选错了哦,还有一个T ...
- 九度OJ 1041:Simple Sorting(简单排序) (排序)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:4502 解决:1680 题目描述: You are given an unsorted array of integer numbers. ...
- 360手机助手: App上架(提交资料)注意事项
提交app资料尤其注意: .keystore和密码?由HBuilder提供公有证书: 签名证书KeyStore证书别名:hbuilder证书密码:123456keystore密码:123456 360 ...