题目链接:Mediocre String Problem - 题库 - 计蒜客
解题思路;
对于s串的某个点i的贡献就是以i点为左边界在s串上有多少种回文串(记为x)这些回文串可以插在中间,那么右端自然是t的前缀,左端就是t前缀的倒置。
求t前缀的倒置不就是将s倒过来看,取求s中的i节点为开头与t的最长前缀公共子串长度吗?(长度记为y)所以这个可以倒过来后用扩展KMP求得。之后对于i点的贡献就是x*y(y是倒置后的相应位置)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 1e6 + 10;
int dp[mx*2],nxt[mx],extend[mx];
int sum[mx];
char s[mx],t[mx],str[mx*2];
void E_init(int len)
{
nxt[0] = len;
extend[0] = nxt[1] = 0;
int j = 0,k = 1;
while(t[k++]==t[j++]) nxt[1]++;
j = k = 0;
while(j<len&&t[j++]==s[k++]) extend[0]++;
}
int M_init(char *p)
{
int len = 0;
str[len++] = '$';
str[len++] = '#';
for(int i=0;p[i];i++)
{
str[len++] = p[i];
str[len++] = '#';
}
return len;
}
void manacher(char *p)
{
int len = M_init(p);
int Max = 0,id,r;
for(int i=1;i<len;i++){
if(i<Max) dp[i] = min(Max-i,dp[2*id-i]);
else dp[i] = 1;
while(str[i+dp[i]]==str[i-dp[i]]) dp[i]++;
if(i+dp[i]>Max) id = i,Max = i + dp[i];
}
for(int i=2;i<len;i++){
if(i=='#') r = (i-3)/2 + 1;
else r = (i-2)/2 + 1;
sum[r-dp[i]/2]++,sum[r]--;
}
for(int i=1;p[i];i++) sum[i] += sum[i-1];
}
void Get(char *c,int len,int *tmp,int po,int pos)
{
int j,k;
for(int i=1;i<len;i++){
int lon = nxt[i-po];
if(i+lon<pos) tmp[i] = lon;
else{
if(pos<i) pos = i;
tmp[i] = pos - i;//先确定他是可以到达p的
j = pos,k = pos - i;
while(j<len&&c[j++]==t[k++]) tmp[i]++;//然后向后继续扩展
po = i,pos = i + tmp[i];//更新po和pos
}
}
}
int main()
{
scanf("%s%s",s,t);
int Slen = strlen(s);
int Tlen = strlen(t);
manacher(s);
reverse(s,s+Slen);
E_init(Tlen);
Get(t,Tlen,nxt,1,1+nxt[1]);
Get(s,Slen,extend,0,extend[0]);
ll ans = 0;
for(int i=1;i<Slen;i++) ans += 1ll*sum[i]*extend[Slen-i];
printf("%lld\n",ans);
return 0;
}