以前觉得这题好难,现在觉得这题还是挺简单
首先看到类似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的更多相关文章

  1. BZOJ3230 相似子串 字符串 SA ST表

    原文链接http://www.cnblogs.com/zhouzhendong/p/9033092.html 题目传送门 - BZOJ3230 题意 给定字符串$s$.长度为$n$. 现在有$Q$组询 ...

  2. 【bzoj3230】相似子串

    Portal -->bzoj3230 Description 给你一个长度为\(n\)的字符串,把它的所有本质不同的子串按字典序大小排序,有\(m\)个询问,对于每一个询问\(x,y\)你需要回 ...

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

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

  4. BZOJ3230 相似子串[后缀数组+二分+st表]

    BZOJ3230 相似子串 给一个串,查询排名i和j的子串longest common suffix和longest common prefix 思路其实还是蛮好想的,就是码起来有点恶心.可以发现后缀 ...

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

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

  6. BZOJ3230: 相似子串

    3230: 相似子串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 913  Solved: 223[Submit][Status]Descripti ...

  7. BZOJ3230 相似子串 【后缀数组】

    题目分析: 容易想到sa排好序之后,子串排名就是前面的子串减去height数组.所以正着做一遍,倒着做一遍就行了. 代码: #include<bits/stdc++.h> using na ...

  8. 2018.11.30 bzoj3230: 相似子串(后缀数组)

    传送门 后缀数组入门题. 建立正反两个后缀数组算就行了. 代码: #include<bits/stdc++.h> #define ri register int using namespa ...

  9. BZOJ3230: 相似子串【后缀数组】

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

随机推荐

  1. iOS UIKit:viewController之Present (3)

    弹出和转换view controller技术是一种快速且简单的方式将新view content展示在屏幕中.目前有两种方式弹出新的view controller:Present方式和segues方式. ...

  2. Sql Server 中事务(begin tran/commit tran/rollback tran)的用法

    ALTER PROCEDURE [dbo].[Proc_Test_commit1]     @result int output, --成功 1; 失败 0     @message nvarchar ...

  3. 零基础学习云计算及大数据DBA集群架构师【预科2015年12月14日周一】

    1.第一天比较轻松,上午填表格,录指纹,拍照片,做自我介绍. 2.下午老师简单介绍了一下PC\交换机\路由器\塔式服务器\机架式服务器(1U\2U)\刀片服务器\磁带机 3.班主任陈老师朱老师,预科秦 ...

  4. CakePHP的blog教程三

    简单的身份验证和授权应用 接着我们blog教程的例子,如果我们想要建立一个根据登录的用户身份来决定其安全访问到正确的urls. 同时我们还有其他的需求: 允许我们的blog有多个作者,每一个作者都可以 ...

  5. .Net framework.

    Figure 1 - .Net Framework The Common Language Runtime (CLR) is the mechanism through which .NET code ...

  6. openwrt advanced configuration

    openwrt高级配置(汗 照着标题就翻译过来了) openwrt Kamikaze 8.09的一般配置文件都在目录 /etc/config 下面,可以使用脚本来调用参数和设置参数. 比如 sbin/ ...

  7. NSDate和NSString的转换及判定是昨天,今天,明天

    用于uidate,picker.. +(NSDate*) convertDateFromString:(NSString*)uiDate{    NSDateFormatter *formatter ...

  8. 文字和表单(checkbox/radio)元素垂直对齐方法,兼容Firefox和IE。

    这几天在做表单时总会碰到复选框(checkbox)和单选框(radio)与文字不对齐的问题,要不是checkbox上浮了,要不是文字上浮.在前端开发过程中,单(复)选框和它们后面的提示文字在不进行任何 ...

  9. 虚拟机VHD格式解析到NTFS文件系统解析

    本来的需求是XEN下的镜像取证,但这篇仅包括他支持的一种格式,就是VHD,此项目从头开始大概用了两周时间,中间遇到了很多让人头大的问题,光是思考的笔记就写了十几页纸,不过实际上并没有那么难,主要是很久 ...

  10. 用arm-linux-gcc v4.3.4交叉编译Qt4.8.3

    1.解压缩 #tar zxvf  qt-everywhere-opensource-src-4.8.3.tar.gz 2. configure #mkdir buildarm-static #cd b ...