bzoj3230
以前觉得这题好难,现在觉得这题还是挺简单
首先看到类似LCP问题不难想到后缀数组吧
前后的相似需要我们分别做一个后缀数组和“前缀数组”(就是把字符串反向然后跑后缀数组)
这道题的难点就在于如何确定子串是什么
考虑到一个有用的结论:任何一个子串都是某一个后缀的某一个前缀
由于做完后缀数组之后,后缀已经按照从小到大排列了
因此考虑相邻名次后缀sa[i]和sa[i-1],然后在这两个后缀间,还夹着一些子串
不难发现,这些子串就是后缀sa[i]从第h[i]+1位开始的前缀
为什么是从h[i]+1开始的前缀呢,因为前缀1~h[i]在一定已经在后缀sa[i-1]出现过了,要避免重复
因此,我们可以计算相邻两个后缀之间不同的子串数目,然后维护前缀和
这样就可以用二分来确定名词为x的子串是哪个后缀的前缀
然后求相似程度不难想到用ST解决 利用LCP(i,j)=min(height[rank[i]+1~rank[j]]) 假定rank[i]<rank[j]
注意这道题名次可能会爆longint,我一开始都想到子串数目会爆longint,可读入的时候竟然忘了用int64,囧……~
var sa,rank,h:array[..,..] of longint;
f:array[..,..,..] of longint;
x,y:array[..] of longint;
d:array[..] of longint;
sum:array[..] of int64;
s1,s2:ansistring;
i,n,t:longint;
p,q:int64; function min(a,b:int64):int64;
begin
if a>b then exit(b) else exit(a);
end; procedure swap(var a,b:longint);
var c:longint;
begin
c:=a;
a:=b;
b:=c;
end; procedure suffix(s:ansistring;k:longint);
var m,i,j:longint;
begin
fillchar(sum,sizeof(sum),);
for i:= to n do
begin
y[i]:=ord(s[i]);
inc(sum[y[i]]);
end;
for i:= to do
inc(sum[i],sum[i-]);
for i:=n downto do
begin
sa[k,sum[y[i]]]:=i;
dec(sum[y[i]]);
end;
p:=;
rank[k,sa[k,]]:=;
for i:= to n do
begin
if (y[sa[k,i]]<>y[sa[k,i-]]) then inc(p);
rank[k,sa[k,i]]:=p;
end;
m:=p;
j:=;
while m<n do
begin
y:=rank[k];
fillchar(sum,sizeof(sum),);
p:=;
for i:=n-j+ to n do
begin
inc(p);
x[p]:=i;
end;
for i:= to n do
if sa[k,i]>j then
begin
inc(p);
x[p]:=sa[k,i]-j;
end; for i:= to n do
begin
rank[k,i]:=y[x[i]];
inc(sum[rank[k,i]]);
end;
for i:= to m do
inc(sum[i],sum[i-]);
for i:=n downto do
begin
sa[k,sum[rank[k,i]]]:=x[i];
dec(sum[rank[k,i]]);
end;
p:=;
rank[k,sa[k,]]:=;
for i:= to n do
begin
if (y[sa[k,i]]<>y[sa[k,i-]]) or (y[sa[k,i]+j]<>y[sa[k,i-]+j]) then inc(p);
rank[k,sa[k,i]]:=p;
end;
m:=p;
j:=j shl ;
end;
h[k,]:=;
p:=;
for i:= to n do
begin
if rank[k,i]= then continue;
j:=sa[k,rank[k,i]-];
while (i+p<=n) and (j+p<=n) and (s[i+p]=s[j+p]) do inc(p);
h[k,rank[k,i]]:=p;
if p> then dec(p);
end;
end; procedure rmq(k:longint);
var t,i,j:longint;
begin
for i:= to n do
f[k,i,]:=h[k,i];
t:=trunc(ln(n)/ln());
for j:= to t do
for i:= to n do
if (i+d[j]-<=n) then
f[k,i,j]:=min(f[k,i,j-],f[k,i+d[j-],j-])
else break;
end; function ask(x,y,k:longint):longint;
var t:longint;
begin
if x=y then exit(n+-sa[k,x]);
if x>y then swap(x,y);
inc(x);
t:=trunc(ln(y-x+)/ln());
exit(min(f[k,x,t],f[k,y-d[t]+,t]));
end; function find(x:int64):longint;
var l,m,r:longint;
begin
l:=;
r:=n;
while l<=r do
begin
m:=(l+r) shr ;
if (sum[m-]<x) and (sum[m]>=x) then exit(m);
if sum[m]<x then l:=m+ else r:=m-;
end;
end; function getans(x,y:int64):int64;
var a,b,aa,bb,c:longint;
begin
a:=find(x); //查找是哪个后缀的前缀
b:=find(y);
aa:=sa[,a]+h[,a]+x-sum[a-]-; //定位前缀数组中的位置
bb:=sa[,b]+h[,b]+y-sum[b-]-;
aa:=rank[,n+-aa];
bb:=rank[,n+-bb];
c:=min(h[,a]+x-sum[a-],h[,b]+y-sum[b-]); //注意这里我们是求子串所在后缀的LCP,可能会超出原来子串的长度
getans:=sqr(min(c,ask(a,b,)))+sqr(min(c,ask(aa,bb,)));
end; begin
readln(n,t);
readln(s1);
s2:='';
for i:=n downto do
s2:=s2+s1[i];
suffix(s1,);
suffix(s2,);
d[]:=;
for i:= to trunc(ln(n)/ln()) do
d[i]:=d[i-]*;
rmq(); //处理ST
rmq();
sum[]:=;
for i:= to n do
sum[i]:=sum[i-]+n+-sa[,i]-h[,i];
for i:= to t do
begin
readln(p,q);
if (p>sum[n]) or (q>sum[n]) then //判断是否超出子串数目
begin
writeln(-);
continue;
end;
writeln(getans(p,q));
end;
end.
bzoj3230的更多相关文章
- BZOJ3230 相似子串 字符串 SA ST表
原文链接http://www.cnblogs.com/zhouzhendong/p/9033092.html 题目传送门 - BZOJ3230 题意 给定字符串$s$.长度为$n$. 现在有$Q$组询 ...
- 【bzoj3230】相似子串
Portal -->bzoj3230 Description 给你一个长度为\(n\)的字符串,把它的所有本质不同的子串按字典序大小排序,有\(m\)个询问,对于每一个询问\(x,y\)你需要回 ...
- 【BZOJ3230】相似子串 后缀数组+二分+RMQ
[BZOJ3230]相似子串 Description Input 输入第1行,包含3个整数N,Q.Q代表询问组数.第2行是字符串S.接下来Q行,每行两个整数i和j.(1≤i≤j). Output 输出 ...
- BZOJ3230 相似子串[后缀数组+二分+st表]
BZOJ3230 相似子串 给一个串,查询排名i和j的子串longest common suffix和longest common prefix 思路其实还是蛮好想的,就是码起来有点恶心.可以发现后缀 ...
- [BZOJ3230]相似子串(后缀数组)
显然可以通过后缀数组快速找到询问的两个串分别是什么,然后正反各建一个后缀数组来求两个串的LCP和LCS即可. #include<cstdio> #include<cstring> ...
- BZOJ3230: 相似子串
3230: 相似子串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 913 Solved: 223[Submit][Status]Descripti ...
- BZOJ3230 相似子串 【后缀数组】
题目分析: 容易想到sa排好序之后,子串排名就是前面的子串减去height数组.所以正着做一遍,倒着做一遍就行了. 代码: #include<bits/stdc++.h> using na ...
- 2018.11.30 bzoj3230: 相似子串(后缀数组)
传送门 后缀数组入门题. 建立正反两个后缀数组算就行了. 代码: #include<bits/stdc++.h> #define ri register int using namespa ...
- BZOJ3230: 相似子串【后缀数组】
Description Input 输入第1行,包含3个整数N,Q.Q代表询问组数. 第2行是字符串S. 接下来Q行,每行两个整数i和j.(1≤i≤j). Output 输出共Q行,每行一个数表示每组 ...
随机推荐
- HTTP协议基础与实验
一. HTTP协议(Hypetext Transfer Protoacal,超文本传输协议) HTTP协议规定了Web基本的运作过程,以及Web服务器之间的通信细节. Http协议采用客户端/服务器端 ...
- ASP.NET 打包下载文件
使用的类库为:ICSharpCode.SharpZipLib.dll 一种是打包整个文件夹,另一种是打包指定的多个文件,大同小异: using ICSharpCode.SharpZipLib.Zip; ...
- kissy
<!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8& ...
- HTML5常用标签
section 板块,用于划分页面的不同区域或者划分文章里不同的节 ↓ header 页面头部或者板块section头部 ↓ footer 页面底部或者section底部 ↓ nav 导航(包含 ...
- 基于事件的异步模式——BackgroundWorker
实现异步处理的方法很多,经常用的有基于委托的方式,今天记录的是基于事件的异步模式.利用BackgroundWorker组件可以很轻松的实现异步处理,并且该组件还支持事件的取消.进度报告等功能.本文以计 ...
- C# - string 转为 DateTime(自定义)
上代码: string dt = " 1 11 1961"; DateTime day; System.Globalization.DateTimeFormatInfo dtFor ...
- What is SaaS?
SaaS, or Software as a Service, describes any cloud service where consumers are able to access softw ...
- hold
嘿嘿,很久没写博客了.一懒一拖一浮躁就不行了. 果然烦心事太多,一直懒得编程.结果还是编程才能平复我啊! 明天那什么,别担心,平常心嘛! 还好,看了几部电影,不算没收获.自己有意思就看看电影,别瞎想啥 ...
- jquery中eq和get的区别与使用方法
$("p").eq(0).css("color") //因为eq(num)返回的是个jq对象,所以可以用jq的方法css使用get来获得第一个p标签的color ...
- Linux常用命令大全(2)
系统信息arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS / ...