【Ybtoj 第7章 例题2】回文子串【哈希】

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


解题思路

(1)我们可以用二分+哈希来做,首先从前后两端分别哈希一次,然后枚举回文串的中心(对称点),二分对称字符串长度,根据哈希直接判断中心点两端字符串是否相同,然后就没了。。

(2)马拉车。。(不是我打这题的重点,解释起来也比较麻烦,就,略过吧。。代码放了,饶了我吧)

PS:长度要分成奇偶两种分别做,奇数时字符串长度为2mid+1,偶数时为2mid。


代码

马拉车 <——写的超棒

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>

using namespace std;

int ans,q,x,y,l,k,cnt,len[3000010];
char s[3000010],c[3000010];

void yu()
{
    s[k]='@';
    for(int i=1; i<=l; i++)
    {
        s[++k]='#';
        s[++k]=c[i];
    }
    s[++k]='#';
    s[++k]='%';
}

int malacher()
{
    int mx=0,sum=0,id=0;
    for(int i=1; i<k; i++)
    {
        if(i<mx)len[i]=min(mx-i,len[id-(i-id)]);
        else len[i]=1;
        while(s[i-len[i]]==s[i+len[i]])len[i]++;
        if(len[i]+i>mx)
        {
            mx=len[i]+i;
            id=i;
            sum=max(sum,len[i]);
        }
    }
    return (sum-1);
}

int main()
{
    scanf("%s",c+1); 
    while(!(c[1]=='E'&&c[2]=='N'&&c[3]=='D'))
    {
    	cnt++;
        l=strlen(c+1);
        k=0;
        memset(len,0,sizeof(len));
        yu();
        ans=malacher();
        printf("Case %d: %d\n",cnt,ans);
		scanf("%s",c+1);
    }
}

二分+哈希

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iomanip>
#include <cmath>
using namespace std;

typedef unsigned long long ull;

ull p=131;
ull a[1000010],base[1000010],b[1000010];
int n,ans,cnt;
string s;

bool check()
{
	if(s[0]=='E'&&s[1]=='N'&&s[2]=='D')
		return 1;
	return 0;
}

void hash()
{
	memset(base,0,sizeof(base));
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	base[0]=1ull;
	for(int i=0; i<n; i++) {
		base[i+1]=base[i]*p;
		a[i+1]=a[i]*p+(s[i]-'a');//正序字符串哈希
	}
	for(int i=n-1; i>=0; i--)
		b[i+1]=b[i+2]*p+(s[i]-'a');//倒序字符串哈希
}

void work()
{
	for(int i=1; i<=n; i++) {//找中心
		int mid=0,l=0,r=n;
		while(l<=r) {//长度奇数
			mid=(l+r)>>1;
			if(i-mid<1||i+mid>n)
			{
				r=mid-1;
				continue;
			}
			if(a[i]-a[i-mid-1]*base[mid+1]==b[i]-b[i+mid+1]*base[mid+1])
			{
				ans=max(ans,mid*2+1);
				l=mid+1;
			}
			else r=mid-1;
		}
		mid=0,l=0,r=n;
		while(l<=r) {//长度偶数
			mid=(l+r)>>1;
			if(i-mid+1<1||i+mid>n)
			{
				r=mid-1;
				continue;
			}
			if(a[i]-a[i-mid]*base[mid]==b[i+1]-b[i+mid+1]*base[mid])
			{
				ans=max(ans,mid*2);
				l=mid+1;
			}	
			else r=mid-1;
		}
	}

}
int main()
{
	cin>>s;
	n=s.size();
	while(!check()) {
		cnt++;
		ans=1;
		hash();
		work();
		printf("Case %d: %d\n",cnt,ans);
		cin>>s;
		n=s.size();
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值