LOJ#6500. 「雅礼集训 2018 Day2」操作 题解

首先考虑一个 \(\Theta(nm)\) 的暴力。

一次操作对差分数组的影响是把两个距离相差k的位置都异或上1,那么我们只需要保证对于模 k 的每个余数的位置上的1的总数为偶数即可,并且答案为相邻两个的位置差的和 / k。

那么对于每组询问,我们只需要做一个差分即可。判断是否有解可以考虑哈希。需要注意细节。

\(\Theta(n+m+k)\)

code :

#include <bits/stdc++.h>
#define LL unsigned long long
using namespace std;
template <typename T> void read(T &x){
	static char ch; x = 0,ch = getchar();
	while (!isdigit(ch)) ch = getchar();
	while (isdigit(ch)) x = x * 10 + ch - '0',ch = getchar();
}
inline void write(int x){ if (x > 9) write(x/10); putchar(x%10+'0'); }
inline void Get(bool &x){
	static char ch; ch = getchar();
	while (!(ch == '0' || ch == '1')) ch = getchar();
	x = ch - '0';
}
const int N = 2000005;
int n,k,m,s[N][2],now[N]; LL sum[N],hv[N],pre[N]; bool a[N];
int main(){
	int i;
	read(n),read(k),read(m); srand(time(NULL));
	for (i = 1; i <= n; ++i) Get(a[i]);
	for (i = 0; i < k; ++i) hv[i] = ((LL)rand() << 45) + ((LL)rand() << 30ull) + ((LL)rand() << 15ull) + (LL)rand();
	for (i = 1; i <= n; ++i){
		pre[i] = pre[i-1],sum[i] = sum[i-1];
		if (a[i] ^ a[i-1]){
			pre[i] ^= hv[i%k];
			sum[i] += i - (now[i%k] << 1);
			now[i%k] = i - now[i%k];
		}
		s[i][0] = now[i%k],s[i][1] = now[(i+1)%k];
	}
	int l,r; LL Hash,ret;
	while (m--){
		read(l),read(r);
		Hash = pre[l] ^ pre[r] ^ (a[l] ? hv[l%k] : 0) ^ (a[r] ? hv[(r+1)%k] : 0);
		if (Hash){ putchar('-'),putchar('1'),putchar('\n'); continue; }
		ret = sum[r] - sum[l];
		if (a[l]) ret -= l - (s[l][0] << 1);
		if (a[r]) ret += (r+1) - (s[r][1] << 1);
		ret /= k;
		write(ret),putchar('\n');
	}
	return 0;
}
posted @ 2020-09-20 17:07  srf  阅读(247)  评论(0编辑  收藏  举报