LOJ#6500. 「雅禮集訓 2018 Day2」操作 題解
阿新 • • 發佈:2020-09-20
首先考慮一個 \(\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; }