以前觉得这题好难,现在觉得这题还是挺简单
首先看到类似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. [转] 整理了一份React-Native学习指南

    自己在学习React-Native过程中整理的一份学习指南,包含 教程.开源app和资源网站等,还在不断更新中.欢迎pull requests! React-Native学习指南 本指南汇集React ...

  2. unity介绍

  3. Microsoft Windows Server 2008 R2 IIS7.5安装指南

    一.IIS安装步骤: 1.安装Windows Server 2008 R2(见 附录一) 2.配置计算机名称和IP地址(见 附录一) 3.配置成员服务器(见 附录一) 4.点击任务栏上的“服务器管理器 ...

  4. Android Activity各启动模式的差异

    Activity共有四种启动模式:standard,singleTop,singleTask,singleInstance 为了方便描述和理解,布局文件.Manifest文件和各个java文件如下: ...

  5. jsp-文件的上传(转).

    该程序的主要代码,我引用网友的,并做了一些改进.上这个帖子的原因之一,是为了修正之前自己的一些误解. 概述: 一些网友,包括我,也曾经试图通过 input type 为 file的控件,获取其文件的完 ...

  6. c# 访问修饰符的访问权限

    1. 访问修饰符. 指定声明的类型和类型成员的可访问性. (1) public:是类型和类型成员的访问修饰符.公共访问是允许的最高访问级别.对访问公共成员没有限制. (2) private:是一个成员 ...

  7. CI 笔记5 (CI3.0 默认控制器,多目录)

    在ci3.x中,不支持多级子目录的默认控制器设置, 解决方法如下: 在index.php中,添加  $routing['directory'] = 'admin';然后在默认的router.php的默 ...

  8. iOS如何准确获取通知

    iOS获取通知需要注意以下三个地方iOS 设备收到一条推送(APNs),用户点击推送通知打开应用时,应用程序根据状态不同进行处理需在 AppDelegate 中的以下两个方法中添加代码以获取apn内容 ...

  9. (java)从零开始之--异常处理(以文件拷贝为例)

    开发过程中避免不了对异常的处理,但是异常的处理又不能乱throw 下面是简单的抛异常处理 public static void CopyFile(String souFile,String dirFi ...

  10. vs2008 下编译jrtplib-3.9.0成功

    jrtplib-3.9.0的编译,终于搞通了.网上搜集了很多资料,自己也调试了很久. 首先,jrtplib-3.9.0是什么不用多说吧,它是一个很牛的老外用C++写的一个开源的RTP协议库,用它可以进 ...