JSOI 2016 扭动的字符串

题面描述

给出两个长度为\(n\)的字符串\(A,B\)

\(S(i,j,k)\)表示把\(A\)中的\([i,j]\)和\(B\)中的\([j,k]\)拼接起来的字符串

问所有回文的\(S(i,j,k)\)或者\(A,B\)中的回文子串的最长长度

思路

枚举回文串的中心。

可以发现,如果能在当前字符串内扩展就尽量扩展,不能扩展了再尝试和另一个字符串匹配。

对于前者,使用\(manacher\)算法

对于后者,二分一个长度,用\(hash\)判断能否匹配。

以上

代码

#include<bits/stdc++.h>
#define pii pair<int,int>
#define mkp(x,y) make_pair(x,y)
using namespace std;
const int sz=2e5+7;
const int p1=998244353;
const int p2=1e8+7;
const int q1=5271314;
const int q2=2374899;
int n,m;
int ans;
int p[2][sz];
char s[2][sz];
char ss[2][sz<<1];
int w[2][sz];
int pre[2][2][sz],suf[2][2][sz];//字符串,哈希,位置
void init(int tp){
int mid=0,r=0;
for(int i=1;i<=m;i++){
if(i<r) p[tp][i]=min(r-i,p[tp][2*mid-i]);
else p[tp][i]=1;
while(ss[tp][i+p[tp][i]]==ss[tp][i-p[tp][i]]) p[tp][i]++;
if(i+p[tp][i]>r) mid=i,r=i+p[tp][i];
}
}
void hash(int tp){
int hs0,hs1;
hs0=hs1=0;
for(int i=1;i<=n;i++){
hs0=(1ll*hs0*q1%p1+s[tp][i])%p1;
hs1=(1ll*hs1*q2%p2+s[tp][i])%p2;
pre[tp][0][i]=hs0;
pre[tp][1][i]=hs1;
}
hs0=hs1=0;
for(int i=n;i>=1;i--){
hs0=(1ll*hs0*q1%p1+s[tp][i])%p1;
hs1=(1ll*hs1*q2%p2+s[tp][i])%p2;
suf[tp][0][i]=hs0;
suf[tp][1][i]=hs1;
}
}
pii gs(int tp,int st,int l){
int sum1=pre[tp][0][st]-1ll*w[0][l]*pre[tp][0][st-l]%p1;
int sum2=pre[tp][1][st]-1ll*w[1][l]*pre[tp][1][st-l]%p2;
if(sum1<0) sum1+=p1;
if(sum2<0) sum2+=p2;
return mkp(sum1,sum2);
}
pii gn(int tp,int st,int l){
int sum1=suf[tp][0][st]-1ll*w[0][l]*suf[tp][0][st+l]%p1;
int sum2=suf[tp][1][st]-1ll*w[1][l]*suf[tp][1][st+l]%p2;
if(sum1<0) sum1+=p1;
if(sum2<0) sum2+=p2;
return mkp(sum1,sum2);
}
int main(){
scanf("%d",&n);
scanf("%s",s[0]+1);
scanf("%s",s[1]+1);
ss[0][0]=ss[1][0]='#';
ss[0][1]=ss[1][1]='|';
for(int i=1;i<=n;i++){
ss[0][2*i]=s[0][i];
ss[1][2*i]=s[1][i];
ss[0][2*i+1]=ss[1][2*i+1]='|';
}
m=2*n+1;
w[0][0]=w[1][0]=1;
for(int i=1;i<=n;i++){
w[0][i]=1ll*w[0][i-1]*q1%p1;
w[1][i]=1ll*w[1][i-1]*q2%p2;
}
init(0),init(1);
hash(0),hash(1);
int L,R,sl,sr,len,l,r,mid;
for(int i=2;i<m;i++){
L=i-p[0][i],R=i+p[0][i];
sl=L/2,sr=R/2-1;
len=p[0][i]-1;
l=0,r=min(sl,n-sr+1);
while(l<r){
mid=(l+r+1)>>1;
if(gs(0,sl,mid)==gn(1,sr,mid)) l=mid;
else r=mid-1;
}
ans=max(ans,len+2*l);
}
for(int i=2;i<m;i++){
L=i-p[1][i],R=i+p[1][i];
sl=L/2+1,sr=R/2;
len=p[1][i]-1;
l=0,r=min(sl,n-sr+1);
while(l<r){
mid=(l+r+1)>>1;
if(gs(0,sl,mid)==gn(1,sr,mid)) l=mid;
else r=mid-1;
}
ans=max(ans,len+2*l);
}
printf("%d\n",ans);
}

最新文章

  1. html、canvas、视频灰度、反色
  2. 关闭dialog(lhgdialog)
  3. PHP中逻辑运算符and/or与||/&amp;&amp;的一个坑
  4. 在spark中操作mysql数据 ---- spark学习之七
  5. Serverlet程序
  6. 解决maven项目将model version改成3.0版本问题
  7. 【转】 xcode中常用快捷键图文并茂解释
  8. bzoj 3698 XWW的难题(有源汇的上下界最大流)
  9. 学习之路十四:客户端调用WCF服务的几种方法小议
  10. Kendo UI开发教程(21): Kendo MVVM 数据绑定(十) Source
  11. Linux下javaweb
  12. PHP学习笔记-4(时间戳)
  13. Oracle SQL优化[转]
  14. bzoj 2588 Count on a tree
  15. [搬运] C# 这些年来受欢迎的特性
  16. 3DMAX中坐标解析
  17. MySQL中 指定字段排序函数field()的用法
  18. 1286 unknown storage engine innodb
  19. abaqus6.14导出网格inp以及导入inp以建模
  20. windows系统中搭建Jenkins服务器

热门文章

  1. Apache虚拟目录实现同一个IP绑定多个域名
  2. Servlet &amp; Filter 执行原理
  3. 重磅发布: 阿里云WAF日志实时分析上线 (含视频)
  4. 计数dp+概率+大数——(抽屉问题解的个数)zoj3380
  5. python相关软件安装流程图解——MySQL 8.0.13安装教程(windows 64位)——MYSQL依赖的软件——MYSQL必须的系统DLL插件——MYSQL真正的安装
  6. JavaScript的函数进阶
  7. HTML5能取代Android和iOS应用程序吗?
  8. clover无缘无故隐藏书签栏原因
  9. passwd的使用例子
  10. Python全栈开发:DOM