bzoj 3230 相似子串——后缀数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3230
作出后缀数组,从 LCP 看每个位置对于本质不同子串的贡献,而且他们已经按前面部分排好序了,所以直接在 sa[ ] 上二分就能找到询问的子串。
找最长公共前缀就用 ht[ ] 和子串的长度比较就行。找最长公共后缀就一开始把原串翻转,做出翻转后的 ht[ ] ,就能查询了。
也可以二分一个最长公共后缀的位置,然后用正常的 ht[ ] 判断。
注意 long long 。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=1e5+,K=;
int n,sa[][N],rk[][N],tp[N],tx[N];ll sm[N];
int ht[][N][K],bin[K],lg[N];
char s[N];
struct Node{int ps,len;};
int Mn(int a,int b){return a<b?a:b;}
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
ll rdl()
{
ll ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
void init()
{
lg[]=;for(int i=;i<=n;i++)lg[i]=lg[i>>]+;
bin[]=;for(int i=;i<=lg[n];i++)bin[i]=bin[i-]<<;
}
void Rsort(int n,int nm,int x)
{
for(int i=;i<=nm;i++)tx[i]=;
for(int i=;i<=n;i++)tx[rk[x][i]]++;
for(int i=;i<=nm;i++)tx[i]+=tx[i-];
for(int i=n;i;i--)sa[x][tx[rk[x][tp[i]]]--]=tp[i];
}
void get_sa(int n,int x)
{
int nm=;
for(int i=;i<=n;i++)tp[i]=i,rk[x][i]=s[i]-'a'+;
Rsort(n,nm,x);
for(int k=;k<=n;k<<=)
{
int tot=;
for(int i=n-k+;i<=n;i++)tp[++tot]=i;
for(int i=;i<=n;i++)
if(sa[x][i]>k)tp[++tot]=sa[x][i]-k;
Rsort(n,nm,x);memcpy(tp,rk[x],sizeof rk[x]);
nm=;rk[x][sa[x][]]=;
for(int i=,u,v;i<=n;i++)
{
u=sa[x][i]+k;v=sa[x][i-]+k;if(u>n)u=;if(v>n)v=;
rk[x][sa[x][i]]=(tp[sa[x][i]]==tp[sa[x][i-]]&&tp[u]==tp[v])?nm:++nm;
}
if(nm==n)break;
}
}
void get_ht(int n,int x)
{
for(int i=,k=,j;i<=n;i++)
{
for(k?k--:,j=sa[x][rk[x][i]-];i+k<=n&&j+k<=n&&s[i+k]==s[j+k];k++);
ht[x][rk[x][i]][]=k;
}
for(int j=;j<=lg[n];j++)
for(int i=;i+bin[j]-<=n;i++)
ht[x][i][j]=Mn(ht[x][i][j-],ht[x][i+bin[j-]][j-]);
}
int get_lcp(int l,int r,int x)
{
if(l==r)return n-l+;
l=rk[x][l]; r=rk[x][r]; if(l>r)swap(l,r);
int d=lg[r-l];
return Mn(ht[x][l+][d],ht[x][r-bin[d]+][d]);
}
Node fnd(ll x)
{
int l=,r=n,ret=;
while(l<=r)
{
int mid=l+r>>;
if(sm[mid]>=x)ret=mid,r=mid-;
else l=mid+;
}
if(!ret)return (Node){,};
int d=n-sa[][ret]+-ht[][ret][];
d=ht[][ret][]+(x-sm[ret-]);
return (Node){sa[][ret],d};
}
int main()
{
n=rdn();int Q=rdn();scanf("%s",s+);init();
get_sa(n,);get_ht(n,);
reverse(s+,s+n+);get_sa(n,);get_ht(n,);
for(int i=;i<=n;i++)
sm[i]=sm[i-]+(n-sa[][i]+)-ht[][i][];
ll x,y; Node a,b;//long long!!!
while(Q--)
{
x=rdl(); y=rdl();//long long!!
a=fnd(x); b=fnd(y);
if(!a.ps||!b.ps){puts("-1");continue;}
x=Mn(get_lcp(a.ps,b.ps,),Mn(a.len,b.len));
y=Mn(get_lcp(n-(a.ps+a.len-)+,n-(b.ps+b.len-)+,),Mn(a.len,b.len));
printf("%lld\n",x*x+y*y);
}
return ;
}
bzoj 3230 相似子串——后缀数组的更多相关文章
- BZOJ 3230 相似子串 | 后缀数组 二分 ST表
BZOJ 3230 相似子串 题面 题解 首先我们要知道询问的两个子串的位置. 先正常跑一遍后缀数组并求出height数组. 对于每一个后缀suffix(i),考虑以i开头的子串有多少是之前没有出现过 ...
- BZOJ 3230: 相似子串(后缀数组)
传送门 解题思路 其实题目挺好想的.首先子串排名可以由后缀数组求得,因为不算重复的,所以后缀数组的每个后缀排名的去掉\(lcp\)的前缀排名为当前后缀的子串排名.这样就可以预处理出每个后缀的\(l,r ...
- BZOJ 3230 相似子串 ——后缀数组
题目的Source好有趣. 我们求出SA,然后求出每一个后缀中与前面本质不同的字符串的个数. 然后二分求出当前的字符串. 然后就是正反两次后缀数组求LCP的裸题了. 要注意,这时两个串的起点可能会相同 ...
- bzoj 3230 相似子串 —— 后缀数组+二分
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3230 先算出每个后缀贡献子串的区间: 然后前缀LCP直接查询,后缀LCP二分长度,查询即可: ...
- BZOJ 1396: 识别子串( 后缀数组 + 线段树 )
这道题各位大神好像都是用后缀自动机做的?.....蒟蒻就秀秀智商写一写后缀数组解法..... 求出Height数组后, 我们枚举每一位当做子串的开头. 如上图(x, y是height值), Heigh ...
- poj 2774 最长公共子串 后缀数组
Long Long Message Time Limit: 4000MS Memory Limit: 131072K Total Submissions: 25752 Accepted: 10 ...
- URAL 1297 最长回文子串(后缀数组)
1297. Palindrome Time limit: 1.0 secondMemory limit: 64 MB The “U.S. Robots” HQ has just received a ...
- poj 1743 Musical Theme(最长重复子串 后缀数组)
poj 1743 Musical Theme(最长重复子串 后缀数组) 有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复 ...
- BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )
二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) -------------------------------------------------- ...
随机推荐
- Win10易升是什么?如何彻底关闭Windows10易升?
很多朋友反馈在使用电脑的时候,突然弹出一个微软Windows10易升的界面,那么Win10易升是什么,怎么样才可以彻底关闭Win10易升呢? win10易升是什么 1.易升是微软官方发布的升级助理或者 ...
- PHP7的五大新特性
如果你使用的是基于 composer 和 PSR-4 的框架,这种写法是否能成功的加载类文件?其实是可以的,composer 注册的自动加载方法是在类被调用的时候根据类的命名空间去查找位置,这种写法对 ...
- 关于YII2中编辑页面全局变量冲突问题
今天做一编辑页面时被一个很小的问题困了许久.由于在YII2框架里高度集成了bootstrp框架,在做一个编辑的页面时出现了一个自定义的功能,自定义的字段非数据库表里的字段,所以需要在模型里单独声明一个 ...
- spark SQL学习(数据源之parquet)
Parquet是面向分析型业务得列式存储格式 编程方式加载数据 代码示例 package wujiadong_sparkSQL import org.apache.spark.sql.SQLConte ...
- AttributeError: module 'matplotlib' has no attribute 'verbose' (pycharm中使用matplotlib 2.2.0的坑)
AttributeError: module 'matplotlib' has no attribute 'verbose' 环境信息 本地系统:win10 本地开发环境:python(3.6.3), ...
- centos 安装jdk/resin/mysql
一.安装JDK 1.判断是否安装 java -version 我的计算机上使用java -version命令,内容如下: java version "1.7.0_45"OpenJD ...
- 《Computational Statistics with Matlab》硬译2
T=; sigma=; thetamin=-;thetamax=; theta=zeros(,T); seed=;rand('state',seed);randn('state',seed); the ...
- Linux 实用指令之查看端口开启情况
netstat -ntlp 查看端口使用情况! netstat -ntlp | grep 80 查看具体的端口是否使用! # netstat -ntlp Active Internet connect ...
- MSSQL复制表操作
1:复制表结构及数据到新表 select * into 目的数据库名.dbo.目的表名 from 原表名 select * into my0735home.dbo.infoMianTest from ...
- tensorflow笔记:使用tf来实现word2vec
(一) tensorflow笔记:流程,概念和简单代码注释 (二) tensorflow笔记:多层CNN代码分析 (三) tensorflow笔记:多层LSTM代码分析 (四) tensorflow笔 ...