P6216 回文匹配

回文匹配

/*
这里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;
}
posted @ 2023-04-10 20:08  basicecho  阅读(53)  评论(0)    收藏  举报