A M形字符串(字符串hash)

登录—专业IT笔试面试备考平台_牛客网(题目链接)
 

题目描述

给一个长度为n的字符串(1<=n<=200000),他只包含小写字母

找到这个字符串多少个前缀是M形字符串.

M形字符串定义如下:

他由两个相同的回文串拼接而来,第一个回文串的结尾字符和第二个字符串的开始字符可以重叠,也就是以下都是M形字符串.

abccbaabccba(由abccba+abccba组成)

abcbaabcba(有abcba+abcba组成)

abccbabccba(由abccba+abccba组成组成,但是中间的1是共用的)

a(一个单独字符

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define db long double
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
#define pi acos(-1)
#define gcd(a, b) __gcd(a,b)
#define lcm(a, b) a/gcd(a,b)*b
#define pii pair<int, int>
using namespace std;

const int N = 2e5 + 5;
const double eps = 1e-4;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
inline ll qpow(ll x, ll y, ll M) { ll ans = 1; while (y) { if (y & 1)ans = ans * x % M; x = x * x % M; y = y >> 1; }return ans % M; }

ll h1[N], h2[N], pp[N], n;
string s;

bool check1(ll l, ll r)//检查长度为r的前缀是否为回文串
{
	if (r % 2 == 1)//当前缀长度是偶数是,中间字符可以无视
	{
		ll x = r / 2;
		l = n - r + 1;
		r = n - x - 1;
		if (h1[x] == ((h2[r] - h2[l - 1] * pp[r - l + 1]) % mod + mod) % mod)
			return true;
	}
	else
	{
		ll x = r / 2;
		l = n - r + 1;
		r = n - x;//长度为偶数时没有中间字符,和奇数判断唯一的区别
		if (h1[x] == ((h2[r] - h2[l - 1] * pp[r - l + 1]) % mod + mod) % mod)
			return true;
	}
	return false;
}

bool check2(ll l, ll r)//检查第一种情况,不重叠
{
	if (r * 2 - 1 <= n &&  h1[r] == ((h1[2 * r - 1] - h1[r - 1] * pp[r]) % mod + mod) % mod)
		return true;
	return false;
}

bool check3(ll l, ll r)//检查第二种情况,有一个字符重叠
{
	if (r * 2 <= n && h1[r] == ((h1[2 * r] - h1[r] * pp[r]) % mod + mod) % mod)
		return true;
	return false;
}


void solve()
{

	cin >> s;
	n = s.size();
	ll p = 233;
	s = " " + s;
	pp[0] = 1;
	for (ll i = 1; i <= n; i++)
		pp[i] = pp[i - 1] * p % mod;
	for (ll i = 1; i <= n; i++)
		h1[i] = (h1[i - 1] * p + s[i]) % mod;//正哈希
	for (ll i = n; i >= 1; i--)
		h2[n - i + 1] = (h2[n - i] * p + s[i]) % mod;//反哈希,用来判断是否为回文串

	ll ans = 0;
	for (ll i = 1; i <= n; i++)
	{
		if (check1(1, i))
		{
			if (check2(1, i))
				ans++;
			if (check3(1, i))
				ans++;
		}
	}
	cout << ans << '\n';
}

int main()
{
	ll t = 1;
	//cin >> t;
	while (t--)
		solve();
	return 0;
}

也算)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值