Strings in the Pocket ZOJ - 4110

本文探讨了字符串匹配及回文串算法的实现,通过分析字符串相等性与回文半径,介绍了一种利用马拉车算法求解的方法。在两字符串不完全相等的情况下,文章提出了一种寻找特定子串并判断其翻转后是否相等的策略,以确定回文串的存在。通过详细的代码解析,读者可以深入了解这一算法的具体应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4110

先看两个字符串是否相等  若相等则直接用马拉车求回文半径即可

否则 找出l和r来 满足[0,l-1]与[r+1,n-1]内两字符串相等 然后看两字符串[l,r]内是否完全相反 若不完全相反 即翻转后仍无法相等则输出0 否则就以(l+r)/2即不相等子串的中心 左右边界同时向外拓展

主要是理解为什么要以不相等子串的中心为中心 假设中心换作其他位置

lef1 | rgt1

lef2 | rgt2 

其中lef1与lef2是不相等子串 rgt1与rgt2 是相等后缀 若翻转后相等 则有rev(lef1)=rgt2 rev(rgt1)=lef2

又因为rgt1=rgt2 所以rev(lef1)=rgt1=rev(lef2) 得lef1=lef2 与假设矛盾 所以必须以不相等子串的中心为中心

 

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e6+10;

char s[2*maxn],t[maxn];
int book[2*maxn];
int n,l;

ll manacher()
{
    ll res;
    int i,j,p,r;
    l=2*n+1;
    for(i=0;i<n;i++){
        s[2*i]='*',s[2*i+1]=t[i];
    }
    s[2*n]='*',s[l]='\0';
    p=0,r=0;
    for(i=0;i<l;i++){
        if(i<r) book[i]=min(book[2*p-i],r-i);
        else book[i]=1;
        while(0<=i-book[i]&&i+book[i]<l&&s[i-book[i]]==s[i+book[i]]){
            book[i]++;
        }
        if(r<i+book[i]){
            p=i,r=i+book[i];
        }
    }
    res=0;
    for(i=0;i<l;i++){
        res+=ll((book[i]-1+i%2)/2);
    }

    return res;
}

int main()
{
    int tt,i,j,pl,pr,ans;
    scanf("%d",&tt);
    while(tt--){
        scanf("%s%s",s,t);
        n=strlen(s),pl=-1;
        for(i=0;i<n;i++){
            if(s[i]!=t[i]){
                pl=i;
                break;
            }
        }
        for(i=n-1;i>=0;i--){
            if(s[i]!=t[i]){
                pr=i;
                break;
            }
        }
        if(pl==-1){
            printf("%lld\n",manacher());
        }
        else{
            for(i=pl,j=pr;i<=pr;i++,j--){
                if(s[i]!=t[j]){
                    break;
                }
            }
            if(i==pr+1){
                ans=1,pl--,pr++;
                while(0<=pl&&pr<n&&s[pl]==s[pr]){
                    ans++,pl--,pr++;
                }
                printf("%d\n",ans);
            }
            else printf("0\n");
        }
    }
    return 0;
}

//aa

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值