题意: 给你个s串和t串 找三元组(i,j,k) 在 s中选取 i -j ,在t中选取 1-k,使他们拼凑出来的是回文串。
题解:首先对于s串倒转,exkmp求s串和t串extend,对s串进行manacher,求每个统计每个回文串的右端点,最后统计答案。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+1000;
void pre_kmp(char x[],int m,int nex[]){
nex[0]=m;
int j=0;
while(j+1<m&&x[j]==x[j+1]) j++;
nex[1]=j;
int k=1;
for(int i=2;i<m;i++){
int p=nex[k]+k-1;
int L=nex[i-k];
if(i+L<p+1) nex[i]=L;
else{
j=max(0,p-i+1);
while(i+j<m&&x[i+j]==x[j]) j++;
nex[i]=j;
k=i;
}
}
}
void ekmp(char x[],int m,char y[],int n,int nex[],ll extend[]){
pre_kmp(x,m,nex);
int j=0;
while(j<n&&j<m&&x[j]==y[j]) j++;
extend[0]=j;
int k=0;
for(int i=1;i<n;i++){
int p=extend[k]+k-1;
int L=nex[i-k];
if(i+L<p+1) extend[i]=L;
else {
j=max(0,p-i+1);
while(i+j<n&&j<m&&y[i+j]==x[j]) j++;
extend[i]=j;
k=i;
}
}
}
char ma[maxn*2]; int mp[maxn*2];
ll st[maxn];
void Manacher(char s[],int len){
int l=0;
ma[l++]='$';
ma[l++]='#';
for(int i=0;i<len;i++){
ma[l++]=s[i];
ma[l++]='#';
}
ma[l]=0;
int mx=0,id=0;
for(int i=0;i<l;i++){
mp[i]=mx>i?min(mp[2*id-i],mx-i):1;
while(ma[i+mp[i]]==ma[i-mp[i]]) mp[i]++;
if(i+mp[i]>mx) {
mx=i+mp[i];
id=i;
}
}
for(int i=2;i<=len*2;i++){ //统计每个回文串的右端点 、差分
st[(i+1)/2-1]++; st[(i+1)/2+mp[i]/2-1]--;
}
for(int i=1;i<len;i++) st[i]+=st[i-1];
}
char s[maxn],t[maxn];
int nex[maxn];
ll extend[maxn];
int main()
{
scanf("%s %s",s,t);
int len=strlen(s);
int len1=strlen(t);
reverse(s,s+len);
ekmp(t,len1,s,len,nex,extend);
Manacher(s,len);
ll ans=0;
for(int i=1;i<len;i++){
ans+=(ll)(extend[i]*st[i-1]); //求结果 extend是最长公共前缀
}
printf("%lld\n",ans);
return 0;
}