bzoj 3230 相似子串——后缀数组
题目: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 相似子串——后缀数组的更多相关文章
- BZOJ 3230 相似子串 | 后缀数组 二分 ST表
BZOJ 3230 相似子串 题面 题解 首先我们要知道询问的两个子串的位置. 先正常跑一遍后缀数组并求出height数组. 对于每一个后缀suffix(i),考虑以i开头的子串有多少是之前没有出现过 ...
- BZOJ 3230: 相似子串(后缀数组)
传送门 解题思路 其实题目挺好想的.首先子串排名可以由后缀数组求得,因为不算重复的,所以后缀数组的每个后缀排名的去掉\(lcp\)的前缀排名为当前后缀的子串排名.这样就可以预处理出每个后缀的\(l,r ...
- BZOJ 3230 相似子串 ——后缀数组
题目的Source好有趣. 我们求出SA,然后求出每一个后缀中与前面本质不同的字符串的个数. 然后二分求出当前的字符串. 然后就是正反两次后缀数组求LCP的裸题了. 要注意,这时两个串的起点可能会相同 ...
- bzoj 3230 相似子串 —— 后缀数组+二分
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3230 先算出每个后缀贡献子串的区间: 然后前缀LCP直接查询,后缀LCP二分长度,查询即可: ...
- BZOJ 1396: 识别子串( 后缀数组 + 线段树 )
这道题各位大神好像都是用后缀自动机做的?.....蒟蒻就秀秀智商写一写后缀数组解法..... 求出Height数组后, 我们枚举每一位当做子串的开头. 如上图(x, y是height值), Heigh ...
- poj 2774 最长公共子串 后缀数组
Long Long Message Time Limit: 4000MS Memory Limit: 131072K Total Submissions: 25752 Accepted: 10 ...
- URAL 1297 最长回文子串(后缀数组)
1297. Palindrome Time limit: 1.0 secondMemory limit: 64 MB The “U.S. Robots” HQ has just received a ...
- poj 1743 Musical Theme(最长重复子串 后缀数组)
poj 1743 Musical Theme(最长重复子串 后缀数组) 有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复 ...
- BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )
二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) -------------------------------------------------- ...
随机推荐
- “玲珑杯”ACM比赛 Round #13 B -- 我也不是B(二分排序)
题意:开始有一个空序列s,一个变量c=0,接着从左往右依次将数组a中的数字放入s的尾部,每放一个数字就检测一次混乱度K,当混乱度k大于M时就清空序列并让c=c+1 K = Bi * Vi(1<= ...
- hdu 5768 Lucky7 中国剩余定理+容斥+快速乘
Lucky7 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem D ...
- vue-cli 一分钟搭建自己的vue项目
创建项目 1.安装全局vue-cli npm install vue-cli -g 2.生成项目模板(my_projuct为项目名称) vue init webpack my_projuct 3.进入 ...
- 框架布局FrameLayout
框架布局FrameLayout 一.简介 二.代码实例 结果图: 代码: 需要注意的代码: imageView_play.setVisibility(View.INVISIBLE); <Fram ...
- LightOJ - 1248 期望
题意:有一个n面筛子,每次扔一下,每面概率相同,要求扔出n面的期望次数 题解:和第三篇论文里的例题一样,算从第i个到第i+1个的概率是(n-i)/n,n面中找n-i个没有扔到过的,期望是n/(n-i) ...
- 卸载MicrosoftBAF(删除C:\CommonFramework\instdata.dat)
发现有个可疑文件夹 C:\CommonFramework ,而且还会不停的删除创建 C:\CommonFramework\instdata.dat 最后被发现这是必应的一个框架程序在捣鬼,在微软论坛里 ...
- C语言之内存四区模型和函数调用模型
内存四区模型 流程说明1.操作系统把物理硬盘代码load到内存2.操作系统把c代码分成四个区3.操作系统找到main函数入口执行 1.内存四区: 一个由c/C++编译的程序占用的内存分为以下几个部 ...
- 在SQL Server中快速删除重复记录
在SQL Server中快速删除重复记录 2006-07-17 21:53:15 分类: SQL Server 开发人员的噩梦——删除重复记录 想必每一位开发人员都有过类似的经历,在对数据库进行查询 ...
- MMU实验实验
SRAM比较贵,访问方便,发出地址就可以, SDRAM比较便宜 2440的启动方式: 1 .NOR启动 0地址指向NOR(BANK0) 2 .NANA启动 0地址指向片内的SRAM(steppin ...
- 一次完整的HTTP请求
HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤: 1:建立TCP连接,TCP的三次握手 在HTTP工作开始之前,Web浏览器首先要通过网络与Web服 ...