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;
}
BZOJ3230 相似子串 字符串 SA ST表的更多相关文章
- BZOJ2534 Uva10829L-gap字符串 字符串 SA ST表
原文链接https://www.cnblogs.com/zhouzhendong/p/9240665.html 题目传送门 - BZOJ2534 题意 有一种形如 $uvu$ 形式的字符串,其中 $u ...
- BZOJ4556 [Tjoi2016&Heoi2016]字符串 SA ST表 二分答案 主席树
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ4556.html 题目传送门 - BZOJ4556 题意 给定一个长度为 $n$ 的字符串 $s$ . ...
- UOJ#219/BZOJ4650 [NOI2016]优秀的拆分 字符串 SA ST表
原文链接http://www.cnblogs.com/zhouzhendong/p/9025092.html 题目传送门 - UOJ#219 (推荐,题面清晰) 题目传送门 - BZOJ4650 题意 ...
- BZOJ3172 [Tjoi2013]单词 字符串 SA ST表
原文链接http://www.cnblogs.com/zhouzhendong/p/9026543.html 题目传送门 - BZOJ3172 题意 输入$n(n\leq 200)$个字符串,保证长度 ...
- bzoj 3230: 相似子串【SA+st表+二分】
总是犯低级错误,st表都能写错-- 正反分别做一遍SA,预处理st表方便查询lcp,然后处理a[i]表示前i个后缀一共有多少个本质不同的子串,这里的子串是按字典序的,所以询问的时候直接在a上二分排名就 ...
- BZOJ2119 股市的预测 字符串 SA ST表
原文链接https://www.cnblogs.com/zhouzhendong/p/9069171.html 题目传送门 - BZOJ2119 题意 给定一个股票连续$n$个时间点的价位,问有多少段 ...
- Codeforces Round #422 (Div. 2)E. Liar sa+st表+dp
题意:给你两个串s,p,问你把s分开顺序不变,能不能用最多k段合成p. 题解:dp[i][j]表示s到了前i项,用了j段的最多能合成p的前缀是哪里,那么转移就是两种,\(dp[i+1][j]=dp[i ...
- BZOJ3230 相似子串[后缀数组+二分+st表]
BZOJ3230 相似子串 给一个串,查询排名i和j的子串longest common suffix和longest common prefix 思路其实还是蛮好想的,就是码起来有点恶心.可以发现后缀 ...
- BZOJ 4556: [Tjoi2016&Heoi2016]字符串(后缀数组 + 二分答案 + 主席树 + ST表 or 后缀数组 + 暴力)
题意 一个长为 \(n\) 的字符串 \(s\),和 \(m\) 个询问.每次询问有 \(4\) 个参数分别为 \(a,b,c,d\). 要你告诉它 \(s[a...b]\) 中的所有子串 和 \(s ...
随机推荐
- python中__init__ ,__del__ &__new__
__new__ __new__方法是用来创建对象,__new__方法需要有一个返回值,这个返回值表示创建出来的对象的引用 __init__ __init__方法在类的一个对象被建立时 ,马上执行.__ ...
- [JavaScript]为JS处理二进制数据提供可能性的WEB API
写这篇博客的起源是在div.io上的一篇文章<你所不知道的JavaScript数组>by 小胡子哥下的评论中的讨论. 因为随着XHR2和现代浏览器的普及,在浏览器当中处理二进制不再向过去那 ...
- ModelSerializer序列化(Apiview)
url部分: url(r'^book/$',views.book.as_view()),url(r'^books/(\d+)/$', views.bookdetail.as_view(),name=' ...
- inode索引详解
理解inode inode是一个重要概念,是理解Unix/Linux文件系统和硬盘储存的基础. 我觉得,理解inode,不仅有助于提高系统操作水平,还有助于体会Unix设计哲学,即如何把底层的复杂性抽 ...
- python-socket编程(入门,网络基础)
一.网络基础 网络建立的目的是为了数据交互(通信) 如何实现通信: 1.建立好底层的物理连接介质 2.有一套统一的通信标准,称之为互联网协议 1.osi七层协议 互联网协议按照功能的不同分为osi七层 ...
- STM32L476应用开发之七:流量的PID控制
在气体分析仪使用过程中,为了力求分析结果的准确性,一般要求通过的气体流量尽可能的稳定.为了保证流量控制的稳定,我们采用PID调节来控制气路阀门的开度. 1.硬件设计 我们采用的流量计为气体质量流量计, ...
- 前端html
前端html html 是一种描述网页的语言,是超文本标记语言 :hyper Text Markup Lauguage 是一种标记语言[标记语言是一套标记标签 markup tag]使用标记标签来 ...
- ubuntu 安装Mysql8.0
1. 去官网下载安装包 下载链接:点击打开链接 https://dev.mysql.com/downloads/mysql/ 如果你的系统是32位选择第一个,64位选择第二个 也可以用wget 下载 ...
- cf965C 二分+推方程
#include<bits/stdc++.h> using namespace std; #define ll long long ll n,k,M,D,anss; ll calc(ll ...
- Nginx详解十四:Nginx场景实践篇之代理服务
代理的作用 Nginx代理 正向代理 反向代理 正向代理和反向代理的区别:代理的对象不一样 正向代理代理的对象是客户端,反向代理代理的对象是服务端 反向代理: 配置语法:proxy_pass URL; ...