马拉车算法——求回文子串个数zoj4110

zoj的测评姬好能卡时间。。

求回文子串的个数:只要把p[i]/2就行了:

  如果s_new[i]是‘#’,算的是没有中心的偶回文串

  反之是奇回文串

/*
给定两个字符串s,t 
结论:s,t不相同的第一个字符下标为l,最后一个字符下标为r
         如果l==r,那么不存在解
        如果l<r,那么翻转s的一个子串时,一定是将s[l]和s[r]互相翻转
反证:假设存在s[l]和s[r+k]的翻转方法,
    因为s[r+k]=t[r+k]=t[l],且s[l]=t[r+k],可得s[l]=t[l],矛盾
l-k同理

所以本题只需要考虑三种情况:
    1.两个串相等:求s的回文子串
    2.l==r,无解
    3.l<r,首先s[l,r]翻转后和t[l,r]相等,然后找以s[l,r]为中心的回文子串 
*/
#include<bits/stdc++.h>
using namespace std;
#define maxn 5000006
char s[maxn],t[maxn],s_new[maxn];
int p[maxn];

int init(){
    int len=strlen(s),j=2;
    s_new[0]='$',s_new[1]='#';
    for(int i=0;i<len;i++){
        s_new[j++]=s[i];
        s_new[j++]='#'; 
    }
    s_new[j]=0;
    return j;
}
long long manacher(){
    long long res=0;
    int len=init(),mx=0,id;
    for(int i=0;i<len;i++){
        if(mx>i)p[i]=min(p[2*id-i],mx-i);
        else p[i]=1;
        while(s_new[i-p[i]]==s_new[i+p[i]])p[i]++;
        if(mx<i+p[i])mx=i+p[i],id=i;
        res+=(long long )p[i]/2;
    }
    return res;
}
int main(){
    int T;cin>>T;
    while(T--){
        scanf("%s%s",s,t);
        int len=strlen(s),l=0x3f3f3f3f,r=0;
        for(int i=0;i<len;i++)
            if(s[i]!=t[i]){l=i;break;}
        for(int i=len-1;i>=0;i--)
            if(s[i]!=t[i]){r=i;break;}
            
        if(l==r){puts("0");continue;} 
        if(l>r){cout<<manacher()<<endl;continue;}
        
        int flag=0;
        for(int i=l,j=r;i<=r;i++,j--)
            if(s[i]!=t[j])flag=1;
        if(flag){puts("0");continue;}
        else {
            int ans=1;
            while(l!=0 && r!=len-1){
                --l;++r;
                if(s[l]==s[r])ans++;
                else break;
            }
            cout<<ans<<endl;
        }
    }
}
原文地址:https://www.cnblogs.com/zsben991126/p/10786167.html