/*
这里sum表示一维前缀和
sum(r-m+1) - sum(l-1)
sum(r-m+1-i) - sum(l-1+i)
所以应该是使用二位前缀和来进行处理
len/2也就是我半径需要的最小长度
有些难模拟,但是就是二维前缀和
最后统计答案的地方是真的绕
*/
#include <bits/stdc++.h>
using namespace std;
const int M=3e6+5;
#define int unsigned int
int ne[M];
void kmp(string s,int n) {
for(int i=2,j=0;i<=n;i++) {
while(j&&s[i]!=s[j+1])j=ne[j];
if(s[i]==s[j+1])j++;
ne[i]=j;
}
}
int sum[M];//二维前缀和
void find(string s,int n,string t,int m) {
for(int i=1,j=0;i<=n;i++) {
while(j&&s[i]!=t[j+1])j=ne[j];
if(s[i]==t[j+1])j++;
if(j==m) {
sum[i-j+1]=1;
j=ne[j];
}
}
}
int p[M];
void manacher(string s,int n) {
s.push_back('@');
for(int i=1,mid=0,r=0;i<=n;i++) {
if(i<=r)p[i]=min(p[2*mid-i],r-i+1);
while(s[i-p[i]]==s[i+p[i]])p[i]++;
if(i+p[i]-1>r)mid=i,r=i+p[i]-1;
}
}
signed main() {
int n,m;
cin>>n>>m;
string s1,s2;
cin>>s1>>s2;
s1=' '+s1,s2=' '+s2;
kmp(s2,m);
find(s1,n,s2,m);
for(int i=1;i<=n;i++)sum[i]+=sum[i-1];
for(int i=1;i<=n;i++)sum[i]+=sum[i-1];//二维前缀和处理
manacher(s1,n);
int ans=0;
for(int i=1;i<=n;i++) {
if(2*p[i]-1<m)continue;
int r=i+p[i]-1,l=i-p[i]+1;
l--;r=r-m+1;
int mid=(l+r)/2;
//这里很绕呀
ans+=sum[r]-sum[mid]-sum[((l+r)&1)?mid:mid-1]+sum[l==0?l:l-1];
}
cout<<ans<<endl;
return 0;
}
标签:P6216,匹配,前缀,int,s2,sum,s1,回文
From: https://www.cnblogs.com/basicecho/p/17304151.html