以前觉得这题好难,现在觉得这题还是挺简单
首先看到类似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. ref和out的区别在c#中 总结

     ref 关键字使参数按引用传递.其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中.简单点说就是,使用了ref和out的效果就几乎和C中使用了指针变量一样.它能够让你 ...

  2. javascript 高级程序设计(三)-数据类型

    ECMAScript 中所有类型的值都有与这两个Boolean值等价的值   数据类型     转换为true的值   转换为false的值 Boolean true   false( String ...

  3. 从创建webservice到发布webservice的一些相关总结

    最近做了一个web服务,开始什么也不懂,就在网上到处找,对于刚毕业的我,感觉没用实际代码经过自己的手写出来,看什么都一头雾水,然后就看到很多人说webservice已经融入WCF..然后就先创建了WC ...

  4. 【转】Angularjs Controller 间通信机制

    在Angularjs开发一些经验总结随笔中提到我们需要按照业务却分angular controller,避免过大无所不能的上帝controller,我们把controller分离开了,但是有时候我们需 ...

  5. 学习java随笔第一篇:搭建java平台(java se)

    电脑系统:windows8 在这里介绍一下java平台的3个版本: Java SE--Java Standard Edition,Java的标准版,主要用于桌面级的应用和数据库开发. Java EE- ...

  6. reactjs 入门

    地址搜集:http://www.cocoachina.com/webapp/20150604/12035.html class 属性需要写成 className ,for 属性需要写成 htmlFor ...

  7. (ternary operator)三元运算符.

    ternary operator: advantage: make a terse simple conditional assignment statement of if-then-else. d ...

  8. NodeJS学习笔记—1.CommonJS规范

    由于现在web开发,越来越重视代码的复用和抽象的封装,为了解决代码的组织结构.管理.复用和部署等问题,现在普遍采用的机制是模块机制(module).CommonJS约定桌面应用程序和服务器应用程序需要 ...

  9. IOS 中得runloop 详细解释

    1.Runloop基础知识- 1.1 字面意思 a 运行循环 b 跑圈 - 1.2 基本作用(作用重大) a 保持程序的持续运行(ios程序为什么能一直活着不会死) b 处理app中的各种事件(比如触 ...

  10. iOS开动画效果之──实现 pushViewController 默认动画效果

    在开发中,视图切换会常常遇到,有时我们不是基于导航控制器的切换,但实际开发中,有时需要做成push效果,下面将如何实现push和pop 默认动画效果代码实例: 一.push默认动画效果 CATrans ...