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;
}