BZOJ3230 相似子串 字符串 SA ST表
原文链接http://www.cnblogs.com/zhouzhendong/p/9033092.html
题目传送门 - BZOJ3230
题意
给定字符串$s$。长度为$n$。
现在有$Q$组询问,每组询问内容如下:
两个正整数$i,j$。
设$s_i,s_j$分别表示$s$的所有本质不同的子串中字典序第$i$小和第$j$小的子串。
请你输出$|lcp(s_i,s_j)|^2+|lcs(s_i,s_j)|^2$。
如果不存在$s_i$或者$s_j$,则输出$-1$。
$n,Q\leq 10^5$
题解
这题大概是我做的前几题$SA$的大整合+升级版吧。
我们考虑如何找到本质不同子串中第$k$大的子串。
我们考虑按照串$s$的后缀大小从小到大处理。
对于排名为$i$的后缀$SA[i]$,考虑它 除了与排名更靠前的其他后缀 的相同前缀以外的前缀所代表的子串。
很显然,这些子串都是本质不同的。根据后缀数组的性质,也很显然,这些串都不同于之前已经计算过的串。不然的话,$height[i]$会更大。
而且,这些子串是按照字典序排的。
现在,我们发现这些后,不需要处理出所有子串。
统计原串后缀排名前$i$的后缀所包含的子串的个数,记为$presum[i]$。
显然,$presum[i]=presum[i-1]+len(SA[i])-height[i]$。
于是我们在查找第$k$大子串的时候就可以通过二分或者倍增来快速地找到第$k$大的子串所在的后缀,然后确定第$k$大的子串就容易了。
至于求两个子串的$LCP$和$LCS$长度,是后缀数组的经典操作,这里就不加赘述了。
代码
#include <bits/stdc++.h>
#define rank r_a_n_k
using namespace std;
typedef long long LL;
const int N=200005;
int n,Q;
int SA[N],rank[N],height[N],tax[N],tmp[N];
int sSA[N],srank[N],sheight[N];
int ST[N][19];
LL presum[N];
char s[N];
void Sort(int n,int m,int SA[],int rank[]){for (int i=0;i<=m;i++)tax[i]=0;for (int i=1;i<=n;i++)tax[rank[i]]++;for (int i=1;i<=m;i++)tax[i]+=tax[i-1];for (int i=n;i>=1;i--)SA[tax[rank[tmp[i]]]--]=tmp[i];
}
bool cmp(int rk[],int x,int y,int w){return rk[x]==rk[y]&&rk[x+w]==rk[y+w];
}
void Suffix_Array(char s[],int n,int SA[],int rank[],int height[]){memset(SA,0,sizeof SA);memset(tmp,0,sizeof tmp);memset(rank,0,sizeof rank);memset(height,0,sizeof height);for (int i=1;i<=n;i++)rank[i]=s[i],tmp[i]=i;int m=127;Sort(n,m,SA,rank);for (int w=1,p=0;p<n;w<<=1,m=p){p=0;for (int i=n-w+1;i<=n;i++)tmp[++p]=i;for (int i=1;i<=n;i++)if (SA[i]>w)tmp[++p]=SA[i]-w;Sort(n,m,SA,rank);for (int i=1;i<=n;i++)swap(rank[i],tmp[i]);rank[SA[1]]=p=1;for (int i=2;i<=n;i++)rank[SA[i]]=cmp(tmp,SA[i],SA[i-1],w)?p:++p;}for (int i=1,j,k=0;i<=n;height[rank[i++]]=k)for (k=max(k-1,0),j=SA[rank[i]-1];s[i+k]==s[j+k];k++);height[1]=0;
}
void Get_ST(int n){memset(ST,0,sizeof ST);for (int i=1;i<=n;i++){ST[i][0]=height[i];for (int j=1;j<19;j++){ST[i][j]=ST[i][j-1];if (i-(1<<(j-1))>0)ST[i][j]=min(ST[i][j],ST[i-(1<<(j-1))][j-1]);}}
}
int Query(int L,int R){int val=floor(log(R-L+1)/log(2));return min(ST[L+(1<<val)-1][val],ST[R][val]);
}
int LCP(int x,int y){if (x==y)return n;x=rank[x],y=rank[y];return Query(min(x,y)+1,max(x,y));
}
int LCS(int x,int y){return LCP(n*2+2-x,n*2+2-y);
}
void GetSubstr(LL k,int &L,int &R){int pos,i;for (pos=0,i=19;i>=0;i--)if (pos+(1<<i)<n&&presum[pos+(1<<i)]<k)pos+=(1<<i);L=sSA[pos+1];R=1LL*L+k-presum[pos]+sheight[pos+1]-1;
}
int main(){scanf("%d%d",&n,&Q);scanf("%s",s+1);s[n+1]='#';for (int i=n*2+1;i>n+1;i--)s[i]=s[n*2+2-i];Suffix_Array(s,n*2+1,SA,rank,height);Get_ST(n*2+1);for (int i=n+1;i<=n*2+1;i++)s[i]=0;Suffix_Array(s,n,sSA,srank,sheight);presum[0]=0;for (int i=1;i<=n;i++)presum[i]=presum[i-1]+(n-sSA[i]+1)-sheight[i];while (Q--){LL k1,k2;int L1,R1,L2,R2;scanf("%lld%lld",&k1,&k2);if (k1>presum[n]||k2>presum[n]){puts("-1");continue;}GetSubstr(k1,L1,R1);GetSubstr(k2,L2,R2);LL len=min(R1-L1+1,R2-L2+1);LL lcp=min(len,(LL)LCP(L1,L2)),lcs=min(len,(LL)LCS(R1,R2));printf("%lld\n",lcp*lcp+lcs*lcs);}return 0;
}
转载于:https://www.cnblogs.com/zhouzhendong/p/BZOJ3230.html
BZOJ3230 相似子串 字符串 SA ST表相关推荐
- BZOJ3172 [Tjoi2013]单词 字符串 SA ST表
原文链接http://www.cnblogs.com/zhouzhendong/p/9026543.html 题目传送门 - BZOJ3172 题意 输入$n(n\leq 200)$个字符串,保证长度 ...
- [SDOI2016] 生成魔咒(后缀数组SA + st表 + set)动态不同子串个数
problem luogu-P4070 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1,21,21,2 拼凑起来形成一个魔咒串 [1,2][1,2][1,2]. 一个魔咒串 ...
- BZOJ3473:字符串(后缀数组,主席树,二分,ST表)
Description 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? Input 第一行两个整数n,k. 接下来n行每行一个字符串. Output 一 ...
- 洛谷P4094 [HEOI2016/TJOI2016]字符串【后缀数组+主席树+st表】
时空限制 2000ms / 256MB 题目描述 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须正确 ...
- sa后缀数组使用合集,包括height数组求LPC和LCS,ST表,单调队列优化。
P5546 [POI2000]公共串 所有串合在一起,每两个串放不同的字符,求一遍后缀数组,然后利用height数组求LCS即可. #include<iostream> #include& ...
- [BZOJ3230]相似子串
[BZOJ3230]相似子串 试题描述 输入 输入第1行,包含3个整数N,Q.Q代表询问组数. 第2行是字符串S. 接下来Q行,每行两个整数i和j.(1≤i≤j). 输出 输出共Q行,每行一个数表示每 ...
- 后缀数组 ---- 2018~2019icpc焦作H题[后缀数组+st表+二分+单调栈]
题目链接 题目大意: 给出nnn个数,定义f[l,r]f[l,r]f[l,r]表示 区间[l,r][l,r][l,r]的最大值,求所有 子区间的最大值的和,要求相同的子区间只能算一次 比如数列 5 6 ...
- UOJ #219 BZOJ 4650 luogu P1117 [NOI2016]优秀的拆分 (后缀数组、ST表)
UOJ #219 BZOJ 4650 luogu P1117 [NOI2016]优秀的拆分 (后缀数组.ST表) 连NOI Day1T1都不会做...看了题解都写不出来还要抄Claris的代码.. 题 ...
- bzoj3277 串 (后缀数组+二分答案+ST表)
常见操作:先把所有串都连到一起,但中间加上一个特殊的符号(不能在原串中/出现过)作为分割 由于全部的子串就等于所有后缀的所有前缀,那我们对于每一个后缀,去求一个最长的前缀,来满足这个前缀在至少K个原串 ...
最新文章
- TensorRT Analysis Report分析报告
- Spring 教程(三) 环境设置
- 谷歌出现新冠肺炎确诊病例,限制员工出行;比尔·盖茨:可能成百年不遇的大流行病...
- 【数据挖掘】基于密度的聚类方法 - DBSCAN 方法 ( DBSCAN 原理 | DBSCAN 流程 | 可变密度问题 | 链条现象 | OPTICS 算法引入 | 聚类层次 | 族序概念 )
- dofuscator C# 混淆器 原来如此
- UA MATH565C 随机微分方程III Ito积分简介
- Python3_实例汇总
- 深入学习 History 对象管理浏览器会话历史
- security和oauth2.0的整合
- 将Android源码集成到Eclipse中的方法
- 在SpringBoot中使用slf4j与logbak
- 云服务器预装什么系统好,云服务器预装什么系统好
- php学习的一些笔记
- 旅游规划 (25 分)(Dijkstra)
- MVC3开发常常遇到的问题及常常使用到的代码片段
- 【终终极版】linux(Ubuntu)下wineQQ的安装办法
- 暗黑破坏神不朽怎么在电脑上玩 暗黑破坏神不朽模拟器教程
- 高级程序员的思维模式
- 大数据周周看:金融科技公司融360赴美IPO,小蓝单车人去楼空,用户押金退还困难
- Mysql上线长时间以后重新发起请求报错
热门文章
- ArcGIS Server for Silverlight 之集群(Simple Clusterer)
- idea中刷新项目快捷键_解决 IDEA 使用过程中让你觉得不爽的一些问题
- mysql表只有frm文件_MYSQL数据文件--.frm文件(只有.frm文件时的表结构恢复)
- 011_TreeMap对键实现了Comparable接口的对象排序
- android 数据存储怎么保存图片_遇到验证码怎么办?Python编写一个验证码图片数据标注GUI程序!...
- 蓝湖怎么切图标注_【蓝湖指北】一张图教你如何选择标注尺寸
- Windows 上看端口 找PID
- Packt.Java.9.High.Performance.2017.11
- docker 保存 环境持久化_18、docker的持久化存储和数据共享
- oracle 的目录是空的,oracle sqlplus在@命令路径中有空格的问题