回文串
Posted betablewaloot
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了回文串相关的知识,希望对你有一定的参考价值。
1694:回文串
时间限制: 1000 ms 内存限制: 262144 KB
【题目描述】
令F(A,B)表示选择一个串的非空前缀A和串B的非空后缀 使得将串S和串T拼接起来之后是回文串的方案数。
现在给定两个串A和B,令Ai表示串A的第i长的后缀,Bi为串B的第i长的前缀。
有Q组询问,第i 组询问给定xi 和yi ,对每组询问求F(Axi,Byi)的值。
【输入】
第一行一个字符串str,表示数据类型。
接下来的两行分别表示字符串A和B。
接下来一行一个正整数Q,表示询问的个数。
接下来Q行,每行两个正整数xi 和 yi。
【输出】
输出Q行,每行一个整数,表示这一组询问的答案。
【输入样例】
B
newionyzz
wyxioiwen
1
1 1
【输出样例】
16
【提示】
【样例解释】
对于样例 1,共有以下 16种方案:
{S=n,T=n};{S=n,T=en};{S=ne,T=n};{S=ne,T=en};
{S=ne,T=wen};{S=new,T=en};{S=new,T=wen};{S=new,T=iwen};
{S=new,T=ioiwen};{S=newi,T=wen};{S=newi,T=iwen};{S=newi,T=oiwen};
{S=newio,T=iwen};{S=newio,T=oiwen};{S=newio,T=ioiwen};{S=newion,T=oiwen}
【数据规模】
对于100%的数据,字符串中只出现小写字母。
子任务编号 子任务分值 max(|A|,|B|)<=8e5, Q<=1e5.
【题解】
首先将B串翻转,方便之后匹配。
对于前缀后缀拼接而成的回文串,出去A串和B串的最长公共前缀后,剩下的必须是一个回文串。
例如
A aba
B abacdqdc
拼接为abacdqdcaba。
此时除去最长公共前缀后是cdqdc
所以我们可以求出A,B中以每一位开头后头有几个回文串,设为f[i],g[i]。
统计答案时枚举A,B公共前缀,则答案为∑f[x+i]+g[y+i]+1。i为两串的公共前缀长度。
求出f,g数组前缀和即可用哈希二分最长公共前缀求解。
所以现在问题剩下求出f,g
可以跑一遍马拉车,对于以i为中心的回文串长度为cj[i]。则对f[i-cj[i]+1]到f[i]都有1的贡献可以差分求解,注意关于‘#’的处理。
时间复杂度
设ma=max(lena,lenb);
O(lena+lenb+Q*log2ma).
代码如下:
#include<bits/stdc++.h> #define int long long #define ull unsigned long long using namespace std; const int N=8e5+5; const int cc=131; const int mo=998244353; int cj[N<<1],n,m,f[N],g[N],q,zc,hu[N<<1],haa2[N],hab2[N],ch2[N]; char modeyong[10],s[N],t[N],c[N<<1]; ull haa[N],hab[N],ch[N]; inline void malache(int pu,int len) { c[0]=‘$‘;c[1]=‘#‘; for(int i=1;i<=len;i++) { if(pu==0) c[i*2]=s[i]; else c[i*2]=t[i]; c[i*2+1]=‘#‘; } int r=0,zai=0; len=len*2+1;c[len+1]=‘)‘; memset(cj,0,sizeof(cj)); for(int i=1;i<=len;i++) { if(i<r) cj[i]=min(r-i,cj[zai*2-i]); else cj[i]=1; while(c[cj[i]+i]==c[i-cj[i]]) cj[i]++; if(cj[i]+i>r) r=i+cj[i],zai=i; } memset(hu,0,sizeof(hu)); for(int i=1;i<=len;i++) { int huu=i-cj[i]+1; if(huu%2==1) huu++; hu[huu]++; huu=i+1; if(huu%2==1) huu++; hu[huu]--; } } inline int read() { char c=getchar(); int x=0,f=1; while(!isdigit(c)) {if(c==‘-‘) f=-1;c=getchar();} while(isdigit(c)) {x=(x<<3)+(x<<1)+c-‘0‘;c=getchar();} return x*f; } inline void get_hash() { ch[0]=1;ch2[0]=1; for(int i=1;i<=N-3;i++) ch[i]=ch[i-1]*cc,ch2[i]=(ch2[i-1]*cc)%mo; for(int i=1;i<=n;i++) haa[i]=haa[i-1]*cc+s[i],haa2[i]=(haa2[i-1]*cc+s[i])%mo; for(int i=1;i<=m;i++) hab[i]=hab[i-1]*cc+t[i],hab2[i]=(hab2[i-1]*cc+t[i])%mo; } inline bool check(int x,int k1,int k2) { ull hu1=haa[k1+x-1]-ch[x]*haa[k1-1]; ull hu2=hab[k2+x-1]-hab[k2-1]*ch[x]; int hu3=(haa2[k1+x-1]-haa2[k1-1]*ch2[x]%mo+mo)%mo; int hu4=(hab2[k2+x-1]-hab2[k2-1]*ch2[x]%mo+mo)%mo; return (hu1==hu2)&&(hu3==hu4); } signed main() { scanf("%s%s%s",modeyong,s+1,t+1); n=strlen(s+1);m=strlen(t+1); reverse(t+1,t+m+1); malache(0,n); for(int i=2;i<=2*n;i+=2) f[i/2]=hu[i]; malache(1,m);zc=max(n,m); for(int i=2;i<=2*m;i+=2) g[i/2]=hu[i]; for(int i=1;i<=n;i++) f[i]+=f[i-1]; for(int i=1;i<=n;i++) f[i]+=f[i-1]; for(int i=1;i<=m;i++) g[i]+=g[i-1]; for(int i=1;i<=m;i++) g[i]+=g[i-1]; get_hash(); q=read(); for(int i=1,x,y;i<=q;i++) { x=read();y=read(); if(x>n||y>m) { cout<<"0 "; continue; } int l=1,r=min(n-x+1,m-y+1),daan=0; while(l<=r) { int mid=(l+r)>>1; if(check(mid,x,y)==1) l=mid+1,daan=mid; else r=mid-1; } cout<<f[min(n,x+daan)]+g[min(m,y+daan)]-f[x]-g[y]+daan<<" "; } return 0; }
以上是关于回文串的主要内容,如果未能解决你的问题,请参考以下文章