题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3230

作出后缀数组,从 LCP 看每个位置对于本质不同子串的贡献,而且他们已经按前面部分排好序了,所以直接在 sa[ ] 上二分就能找到询问的子串。

找最长公共前缀就用 ht[ ] 和子串的长度比较就行。找最长公共后缀就一开始把原串翻转,做出翻转后的 ht[ ] ,就能查询了。

也可以二分一个最长公共后缀的位置,然后用正常的 ht[ ] 判断。

注意 long long 。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=1e5+,K=;
int n,sa[][N],rk[][N],tp[N],tx[N];ll sm[N];
int ht[][N][K],bin[K],lg[N];
char s[N];
struct Node{int ps,len;};
int Mn(int a,int b){return a<b?a:b;}
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
ll rdl()
{
ll ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
void init()
{
lg[]=;for(int i=;i<=n;i++)lg[i]=lg[i>>]+;
bin[]=;for(int i=;i<=lg[n];i++)bin[i]=bin[i-]<<;
}
void Rsort(int n,int nm,int x)
{
for(int i=;i<=nm;i++)tx[i]=;
for(int i=;i<=n;i++)tx[rk[x][i]]++;
for(int i=;i<=nm;i++)tx[i]+=tx[i-];
for(int i=n;i;i--)sa[x][tx[rk[x][tp[i]]]--]=tp[i];
}
void get_sa(int n,int x)
{
int nm=;
for(int i=;i<=n;i++)tp[i]=i,rk[x][i]=s[i]-'a'+;
Rsort(n,nm,x);
for(int k=;k<=n;k<<=)
{
int tot=;
for(int i=n-k+;i<=n;i++)tp[++tot]=i;
for(int i=;i<=n;i++)
if(sa[x][i]>k)tp[++tot]=sa[x][i]-k;
Rsort(n,nm,x);memcpy(tp,rk[x],sizeof rk[x]);
nm=;rk[x][sa[x][]]=;
for(int i=,u,v;i<=n;i++)
{
u=sa[x][i]+k;v=sa[x][i-]+k;if(u>n)u=;if(v>n)v=;
rk[x][sa[x][i]]=(tp[sa[x][i]]==tp[sa[x][i-]]&&tp[u]==tp[v])?nm:++nm;
}
if(nm==n)break;
}
}
void get_ht(int n,int x)
{
for(int i=,k=,j;i<=n;i++)
{
for(k?k--:,j=sa[x][rk[x][i]-];i+k<=n&&j+k<=n&&s[i+k]==s[j+k];k++);
ht[x][rk[x][i]][]=k;
}
for(int j=;j<=lg[n];j++)
for(int i=;i+bin[j]-<=n;i++)
ht[x][i][j]=Mn(ht[x][i][j-],ht[x][i+bin[j-]][j-]);
}
int get_lcp(int l,int r,int x)
{
if(l==r)return n-l+;
l=rk[x][l]; r=rk[x][r]; if(l>r)swap(l,r);
int d=lg[r-l];
return Mn(ht[x][l+][d],ht[x][r-bin[d]+][d]);
}
Node fnd(ll x)
{
int l=,r=n,ret=;
while(l<=r)
{
int mid=l+r>>;
if(sm[mid]>=x)ret=mid,r=mid-;
else l=mid+;
}
if(!ret)return (Node){,};
int d=n-sa[][ret]+-ht[][ret][];
d=ht[][ret][]+(x-sm[ret-]);
return (Node){sa[][ret],d};
}
int main()
{
n=rdn();int Q=rdn();scanf("%s",s+);init();
get_sa(n,);get_ht(n,);
reverse(s+,s+n+);get_sa(n,);get_ht(n,);
for(int i=;i<=n;i++)
sm[i]=sm[i-]+(n-sa[][i]+)-ht[][i][];
ll x,y; Node a,b;//long long!!!
while(Q--)
{
x=rdl(); y=rdl();//long long!!
a=fnd(x); b=fnd(y);
if(!a.ps||!b.ps){puts("-1");continue;}
x=Mn(get_lcp(a.ps,b.ps,),Mn(a.len,b.len));
y=Mn(get_lcp(n-(a.ps+a.len-)+,n-(b.ps+b.len-)+,),Mn(a.len,b.len));
printf("%lld\n",x*x+y*y);
}
return ;
}

bzoj 3230 相似子串——后缀数组的更多相关文章

  1. BZOJ 3230 相似子串 | 后缀数组 二分 ST表

    BZOJ 3230 相似子串 题面 题解 首先我们要知道询问的两个子串的位置. 先正常跑一遍后缀数组并求出height数组. 对于每一个后缀suffix(i),考虑以i开头的子串有多少是之前没有出现过 ...

  2. BZOJ 3230: 相似子串(后缀数组)

    传送门 解题思路 其实题目挺好想的.首先子串排名可以由后缀数组求得,因为不算重复的,所以后缀数组的每个后缀排名的去掉\(lcp\)的前缀排名为当前后缀的子串排名.这样就可以预处理出每个后缀的\(l,r ...

  3. BZOJ 3230 相似子串 ——后缀数组

    题目的Source好有趣. 我们求出SA,然后求出每一个后缀中与前面本质不同的字符串的个数. 然后二分求出当前的字符串. 然后就是正反两次后缀数组求LCP的裸题了. 要注意,这时两个串的起点可能会相同 ...

  4. bzoj 3230 相似子串 —— 后缀数组+二分

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3230 先算出每个后缀贡献子串的区间: 然后前缀LCP直接查询,后缀LCP二分长度,查询即可: ...

  5. BZOJ 1396: 识别子串( 后缀数组 + 线段树 )

    这道题各位大神好像都是用后缀自动机做的?.....蒟蒻就秀秀智商写一写后缀数组解法..... 求出Height数组后, 我们枚举每一位当做子串的开头. 如上图(x, y是height值), Heigh ...

  6. poj 2774 最长公共子串 后缀数组

    Long Long Message Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 25752   Accepted: 10 ...

  7. URAL 1297 最长回文子串(后缀数组)

    1297. Palindrome Time limit: 1.0 secondMemory limit: 64 MB The “U.S. Robots” HQ has just received a ...

  8. poj 1743 Musical Theme(最长重复子串 后缀数组)

    poj 1743 Musical Theme(最长重复子串 后缀数组) 有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复 ...

  9. BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )

    二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) -------------------------------------------------- ...

随机推荐

  1. HDU 5704

    题意:n个人参加一个游戏,每个人选择0-100范围的数.m为选择的所有数的平均数*2/3,选择的数<=m且距离m最近的人获胜,若同时有多人满足条件则随机抽取胜者.如果一个人选的数,比m小,且相距 ...

  2. BZOJ4487 [Jsoi2015]染色问题

    BZOJ4487 [Jsoi2015]染色问题 题目描述 传送门 题目分析 发现三个限制,大力容斥推出式子是\(\sum_{i=0}^{N}\sum_{j=0}^{M}\sum_{k=0}^{C}(- ...

  3. 未来简史之数据主义(Dataism)

    https://www.jianshu.com/p/8147239c9cb0?from=singlemessage junjguo 关注 2017.04.24 22:08* 字数 8116 阅读 31 ...

  4. scala学习手记40 - case表达式里的模式变量和常量

    再来看一下之前的一段代码: def process(input: Any) { input match { case (a: Int, b: Int) => println("Proc ...

  5. cmake的使用方法

    4. CMakeLists.txt剖析4.1 cmake_minimum_required命令 cmake_minimum_required (VERSION 2.6) 规定cmake程序的最低版本. ...

  6. MVVM4

    原地址(内容更丰富):http://www.cnblogs.com/888h/category/269092.html MVVM架构的简单解析   图1 View.ViewModel.Model之间的 ...

  7. 使用Monkey对apk做稳定性测试

    认识Monkey 官方文档:https://developer.android.com/studio/test/monkey.html 什么是Monkey? Monkey是Android中的一个命令行 ...

  8. 蓝盾第三代AI防火墙分析

    蓝盾第三代AI防火墙是国内首个“AI-Enabled”的防火墙.有别于市场上第一代特征识别.第二代应用识别防火墙.传统安全网关,需要依赖于签名和特征库技术对威胁进行检查,效率较低且存在大量误报漏报,特 ...

  9. 转: 更高的压缩比,更好的性能–使用ORC文件格式优化Hive

    Hive从0.11版本开始提供了ORC的文件格式,ORC文件不仅仅是一种列式文件存储格式,最重要的是有着很高的压缩比,并且对于MapReduce来说是可切分(Split)的.因此,在Hive中使用OR ...

  10. 在SQL Server中快速删除重复记录

     在SQL Server中快速删除重复记录 2006-07-17 21:53:15 分类: SQL Server 开发人员的噩梦——删除重复记录 想必每一位开发人员都有过类似的经历,在对数据库进行查询 ...