CF1320D Reachable Strings(hash)

Description

给定一个 01 01 01 串。每次询问两个等长的子串,求是否可以从一个经过数次变换变成另一个,变换操作的定义是每次选定一个包含 110 110 110 011 011 011 的子串,将其中的 110 110 110 换成 011 011 011 或将其中的 011 011 011 换成 110 110 110

1 ≤ n , q ≤ 2 × 1 0 5 1 \leq n,q \leq 2 \times 10^5 1n,q2×105

Solution

011 011 011 110 110 110 的变换本质上是将 0 0 0 移动 2 2 2 位。具体的,一个 0 可以向左或向右移动 2 2 2 位,前提是移动的路径上没有 0 0 0

如果将串分成若干段,每一段只有一个 0 0 0。如果 0 0 0 在偶数位,那么这个 0 0 0 可以移动到这个段上偶数位,如果 0 0 0 在奇数位,那么这个 0 0 0 可以移动到这个奇数位。这意味着如果两个字符串 0 0 0 的出现位置的奇偶性对应,那么它们可以通过变换相同,奇偶性是指的选定子串的奇偶性。

所以可以 01 01 01 串进行奇偶性 hash。要写两个 hash,分别表示当前位在询问子串中是奇数位或偶数位的 hash。同时预处理一个 Base 的幂次,每个前缀中 0 0 0 的个数即可。

Code

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 5, INF = 0x3f3f3f3f, p = 1e9 + 7, Base = 233;
inline int read() {
	int x = 0, f = 0; char ch = 0;
	while (!isdigit(ch)) f |= ch == '-', ch = getchar();
	while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
	return f ? -x : x;
}
char s[N];
int power[N], cnt[N], hs[N][2];
int get(int l, int r) {
	return (hs[r][l & 1] - hs[l - 1][l & 1] * power[cnt[r] - cnt[l - 1]] % p + p) % p;
}
signed main() {
	int n = read(); scanf("%s", s + 1);
	int Q = read();
	power[0] = 1;
	for (int i = 1; i <= n; i++) {
		power[i] = power[i - 1] * Base % p, cnt[i] = cnt[i - 1];
		hs[i][0] = hs[i - 1][0], hs[i][1] = hs[i - 1][1];
		if (s[i] == '0') {
			cnt[i]++;
			hs[i][0] = (hs[i - 1][0] * Base + (i & 1) + 1) % p, hs[i][1] = (hs[i - 1][1] * Base + (i & 1 ^ 1) + 1) % p;
		}
	}
	while (Q--) {
		int l1 = read(), l2 = read(), len = read();
		if (get(l1, l1 + len - 1) == get(l2, l2 + len - 1)) puts("Yes");
		else puts("No");
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值