题目: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. Spring AOP(1)

  2. AI理论学习笔记(一):深度学习的前世今生

    AI理论学习笔记(一):深度学习的前世今生 大家还记得以深度学习技术为基础的电脑程序AlphaGo吗?这是人类历史中在某种意义的第一次机器打败人类的例子,其最大的魅力就是深度学习(Deep Learn ...

  3. ()IT 职场经验)一位10年Java工作经验的架构师的经验分享,感觉很受用。

    阿里巴巴技术大牛黄勇的经验分享,感觉很受用. 关于IT 职场经验 1. 把技术当成工具 技术这东西,其实一点都不神秘,它只不过是一个工具,用这个工具可以帮助我们解决实际问题,就这么简单. 我们每天在面 ...

  4. 解决com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Specified key was too long; max key length is 767 bytes异常

    错误截图: 解决方法: 用root进入mysql终端,执行以下命令: alter database hive character set latin1;

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

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

  6. Hibernate -- 项目结构模型改造, 加 Utils 和 Dao层

    示例代码: App.java 模拟客户端 /** * 模拟客户端 */ public class App { @Test public void saveCustomer(){ CustomerDao ...

  7. NumPy数组属性

    NumPy - 数组属性 这一章中,我们会讨论 NumPy 的多种数组属性. ndarray.shape 这一数组属性返回一个包含数组维度的元组,它也可以用于调整数组大小. 示例 1 import n ...

  8. JavaScript tips —— 谈谈数组乱序

    前言 先看一个段代码 function randArr (arr) { return arr.sort(() => { return (Math.random() - 0.5); }); } 目 ...

  9. POJ3275:Ranking the Cows(Bitset加速floyd求闭包传递)

    Each of Farmer John's N cows (1 ≤ N ≤ 1,000) produces milk at a different positive rate, and FJ woul ...

  10. 利用大数据技术处理海量GPS数据

    我秀中国物联网地图服务平台目前接入的监控车辆近百万辆,每天采集GPS数据7亿多条,产生日志文件70GB,使用传统的数据处理方式非常耗时. 比如,仅仅对GPS做一些简单的统计分析,程序就需要几个小时才能 ...