字符串Hash例题详解

1.Codeforces 898F Restoring the Expression



题目大意:给定一个字符串,将其划分成三个部分,使其满足一个加法等式。

设计思路:在这里首先我们考虑假定和为    n    \;n\; n位数,那么两个加数的位数肯定都不会超过    n    \;n\; n,并且其中一个加数一定是    n    \;n\; n位或者    n − 1    \;n-1\; n1位。这样我们先求出整个字符串的    H a s h    \;Hash\; Hash函数,这里    b a s e    \;base\; base    10    \;10\; 10便于加法计算,然后枚举等号的位置,判断三个字符串的关系。

Solution:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
const ll base = 10;
const ll mod1 = 1e9 + 7, mod2 = 1e9 + 9;
int len;
char s[maxn];
ll res1, res2;
ll Hash1[maxn], Hash2[maxn], p1[maxn], p2[maxn];
inline  ll getHash1(int l, int r)
{
   
	return ((Hash1[r] - Hash1[l - 1] * p1[r - l + 1]) % mod1 + mod1) % mod1;
}
inline ll getHash2(int l, int r)
{
   
	return ((Hash2[r] - Hash2[l - 1] * p2[r - l + 1]) % mod2 + mod2) % mod2;
}
inline void write(int pos1,int pos2)
{
   
	for (int i = 1; i <= pos1; i++)
	{
   
		putchar(s[i]);
	}
	putchar('+');
	for (int i = pos1 + 1; i <= pos2; i++)
	{
   
		putchar(s[i]);
	}
	putchar('=');
	for (int i = pos2 + 1; i <= len; i++)
	{
   
		putchar(s[i]);
	}
	putchar(10);
}
inline bool check(int l, int r)
{
   
	if (r - l > 1)		//b不是1位数,要判断其是否含前导0,如果有则不符合要求
	{
   
		if (s[l + 1] == '0')
			return false;
	}
	if (len - r > 1)	//x不是1位数,要判断其是否含前导0,如果有则不符合要求
	{
   
		if (s[r + 1] == '0')
			return false;
	}
	ll a1 = getHash1(1, l), a2 = getHash2(1, l);
	ll b1 = getHash1(l + 1, r), b2 = getHash2(l + 1, r);
	ll c1 = getHash1(r + 1, len), c2 = getHash2(r + 1, len);
	if ((a1 + b1) % mod1 == c1 && (a2 + b2) % mod2 == c2)
	{
   
		write(l, r);
		return true;
	}
	return false;
}
int main()
{
   
	cin >> s + 1;
	len = (int)strlen(s + 1);
	if (s[1] == '0')		//如果第一位是0,那么只能是0+b=c的情况
	{
   
		write(1, (len + 1) / 2);
		return 0;
	}
	p1[0] = p2[0] = 1;
	for (int i = 1; i <= len; i++)
	{
   
		Hash1[i] = (Hash1[i - 1] * base + s[i] - '0') % mod1;
		Hash2[i] = (Hash2[i - 1] * base + s[i] - '0') % mod2;
		p1[i] = p1[i - 1] * base % mod1;
		p2[i] = p2[i - 1] * base % mod2;
	}
	for (int i = 1, j = len / 2; i <= j; i++)
	{
   
		if (len - 2 * i <= i)
		{
   
			
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值