【Manacher】Strings in the Pocket (ZOJ-4110)

链接

ZOJ-4110

题意

给 你 两 个 串 s 和 t , 翻 转 一 次 s 串 的 一 个 区 间 [ l , r ] , 问 有 多 少 对 l , r 使 得 翻 转 后 的 s 串 等 于 t 串 。 给你两个串s和t,翻转一次s串的一个区间[l,r],问有多少对l,r使得翻转后的s串等于t串。 st,s[l,r],l,r使st

题解

s = t 时 , a n s = s 串 中 回 文 个 数 , 可 由 M a n a c h e r 算 法 求 得 。 s=t时,ans=s串中回文个数,可由Manacher算法求得。 s=tans=sManacher
s ≠ t 时 , 找 出 最 左 最 右 的 不 等 坐 标 l 、 r , 先 判 断 区 间 [ l , r ] 翻 转 后 s 、 t 串 是 否 相 等 , 不 相 等 则 无 解 ; s \not = t时,找出最左最右的不等坐标l、r,先判断区间[l,r]翻转后s、t串是否相等,不相等则无解; s=tlr[lr]st
相 等 的 话 就 将 l 、 r 向 外 扩 展 , 看 是 否 一 致 。 a n s = 扩 展 次 数 + 1 相等的话就将l、r向外扩展,看是否一致。ans=扩展次数+1 lrans=+1

代码

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;

#define ll long long
void manacher(char *str,ll *hw);
string s,t;
char str[5006000];
ll hw[5006000];
ll n,T,l,r,ans,f;
int main(){
	cin>>T;
	while(T--)
	{
		cin>>s>>t;
		l=r=-1;
		ans=0;
		n=s.size();
		for(int i=0;i<n;i++)
		{
			if(s[i]!=t[i])
			{
				l=i;
				break;
			}
			str[i]=s[i];
		}
		if(l==-1)
		{
			manacher(str,hw);
			for(int i=0;i<n;i++)ans+=hw[i]/2;
		}
		else
		{
			for(int i=n-1;i>=0;i--)
			{
				if(s[i]!=t[i])
				{
					r=i;
					break;
				}
			}
			f=1;
			for(int i=l;i<=r;i++)
			{
				if(s[i]!=t[l+r-i])
				{
					f=0;
					break;
				}
			}
			if(f)
			{
				while(l>=0&&r<n)
				{
					if(s[l]!=t[r])break;
					l--;r++;ans++;
				}
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}
void change(char *str)
{
    str[0]=str[1]='#';
    for(int i=0; i<n; i++)
    {
        str[i*2+2]=s[i];
        str[i*2+3]='#';
    }
    n=n*2+2;
    str[n]=0;
}
void manacher(char *str,ll *hw)
{
	change(str);
    int maxright=0,mid;
    for(int i=1; i<n; i++)
    {
        if(i<maxright)
            hw[i]=min(hw[(mid<<1)-i],hw[mid]+mid-i);
        else
            hw[i]=1;
        for(; str[i+hw[i]]==str[i-hw[i]]; ++hw[i]);
        if(hw[i]+i>maxright)
        {
            maxright=hw[i]+i;
            mid=i;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值