BZOJ3230 相似子串

给一个串,查询排名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表]的更多相关文章

  1. BZOJ 3230 相似子串 | 后缀数组 二分 ST表

    BZOJ 3230 相似子串 题面 题解 首先我们要知道询问的两个子串的位置. 先正常跑一遍后缀数组并求出height数组. 对于每一个后缀suffix(i),考虑以i开头的子串有多少是之前没有出现过 ...

  2. [BZOJ4310] 跳蚤 - 后缀数组,二分,ST表

    [BZOJ4310] 跳蚤 Description 首先,他会把串分成不超过 \(k\) 个子串,然后对于每个子串 \(S\) ,他会从 \(S\) 的所有子串中选择字典序最大的那一个,并在选出来的 ...

  3. bzoj 3230 相似子串 —— 后缀数组+二分

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3230 先算出每个后缀贡献子串的区间: 然后前缀LCP直接查询,后缀LCP二分长度,查询即可: ...

  4. [BZOJ3230]相似子串(后缀数组)

    显然可以通过后缀数组快速找到询问的两个串分别是什么,然后正反各建一个后缀数组来求两个串的LCP和LCS即可. #include<cstdio> #include<cstring> ...

  5. 【BZOJ3230】相似子串 后缀数组+二分+RMQ

    [BZOJ3230]相似子串 Description Input 输入第1行,包含3个整数N,Q.Q代表询问组数.第2行是字符串S.接下来Q行,每行两个整数i和j.(1≤i≤j). Output 输出 ...

  6. UOJ #219 BZOJ 4650 luogu P1117 [NOI2016]优秀的拆分 (后缀数组、ST表)

    连NOI Day1T1都不会做...看了题解都写不出来还要抄Claris的代码.. 题目链接: (luogu)https://www.luogu.org/problemnew/show/P1117 ( ...

  7. [BZOJ3277/BZOJ3473] 串 - 后缀数组,二分,双指针,ST表,均摊分析

    [BZOJ3277] 串 Description 现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). Solution 首先将所有串连 ...

  8. BZOJ4556:[TJOI\HEOI2016]字符串(后缀数组,主席树,二分,ST表)

    Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱 ...

  9. BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )

    二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) -------------------------------------------------- ...

随机推荐

  1. 36:字符串排序SortString

    题目描述:编写一个程序,将输入字符串中的字符按如下规则排序. 规则1:英文字母从A到Z排列,不区分大小写. 如,输入:Type 输出:epTy 规则2:同一个英文字母的大小写同时存在时,按照输入顺序排 ...

  2. 将C#文档注释生成.chm帮助文档(转)

    由于最近需要把以前的一个项目写一个文档,但一时又不知道写成怎样的,又恰好发现了可以生成chm的工具,于是乎我就研究了下,感觉还不错,所以也给大家分享下.好了,不多废话,下面就来实现一下吧. 生成前的准 ...

  3. 浅谈iOS中MVVM的架构设计与团队协作【转载】

    今天写这篇文章是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇文章的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...

  4. IOS-4-面试题1:黑马程序猿IOS面试题大全

    一.多线程网络 1. 多线程的底层实现? 1> 首先搞清楚什么是线程.什么是多线程 2> Mach是第一个以多线程方式处理任务的系统.因此多线程的底层实现机制是基于Mach的线程 3> ...

  5. CentOS下安装python3.x版本

    现在python都到了3.x版本,但是centos中自带的python仍然是2.7版本的,所以想把python换成3.x版本的. 但是这个地方有个坑,你要是直接编译安装了python3.x之后,估计你 ...

  6. C语言高速入门系列(四)

    C语言高速入门系列(四) C语言数组 ---------转载请注明出处:coder-pig 贴心小提示:假设图看不清晰可右键另存为,应该就非常清晰了; 注意上面的代码都要自己过一遍哦! 本节引言: 经 ...

  7. 九度OJ 1150:Counterfeit Dollar(假美元) (分析、检验)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:485 解决:215 题目描述: Sally Jones has a dozen Voyageur silver dollars. Howev ...

  8. Linux线程的几种结束方式

    Linux创建线程使用 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) ...

  9. windows10怎么开机启动虚拟机

    将如下脚本添加到windows计划任务中即可 "D:\Program Files (x86)\VMware\VMware Workstation\vmplayer.exe" &qu ...

  10. smokeping 出现的问题

    Global symbol "%Config" requires explicit package name at /usr/lib64/perl5/lib.pm line 10. ...