CF1511G Chips on a Board
比较有启发性的一道题。
询问是最简单的 nim 游戏,不难发现若一列上有两个棋子,那么这两个棋子对于答案是没有贡献的,因此可以令 \(c_i\) 表示第 \(i\) 列棋子个数是否为奇数。那么询问则为
\[\bigoplus_{i=l}^r [c_i = 1] (i - l) \]这个东西貌似可以使用 Trie 维护变成裸的莫队,但是比较丑陋。考虑拆位,那么对第 \(p\) 维产生贡献的 \(i\) 一定形如若干 \(2^{p+1}\) 连续段中的前半部分,且每段的第一个位置二进制下的前 \((p+1)\) 位是固定的,这启发我们可以把询问差分后离线下来,将前 \(p+1\) 位用一个桶来存储答案,然后扫一遍即可求出答案。
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
namespace IO {
#define isdigit(x) (x >= '0' && x <= '9')
template<typename T>
inline void read(T &x) {
x = 0; char ch = getchar(); int f = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
if(f) x = -x;
}
template<typename T>
inline void write(T x) {
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
#undef isdigit
}
using namespace IO;
const int N = 4e5 + 10;
int n, m, Q;
int c[N], pre[N];
int buc[N];
struct Query {
int l, r, ans;
}q[N];
vector<int> vec[N];
int main() {
read(n), read(m);
for(int i = 1, x; i <= n; ++i)
read(x), c[x] ^= 1;
puts("");
read(Q);
for(int i = 1; i <= Q; ++i) {
read(q[i].l), read(q[i].r);
vec[q[i].l - 1].emplace_back(i);
vec[q[i].r].emplace_back(i);
}
for(int i = 1; i <= 2 * m; ++i)
pre[i] = pre[i - 1] ^ c[i];
for(int i = 0; i <= 17; ++i) {
int u = (1 << (i + 1)) - 1, len = (1 << i);
memset(buc, 0, sizeof buc);
for(int j = 1; j <= m; ++j) {
buc[j & u] ^= pre[j - 1] ^ pre[j + len - 1];
for(int x : vec[j]) {
int suf = (q[x].l + (1 << i)) & u;
if(j < suf) continue;
int lst = (j - suf) >> (i + 1) << (i + 1) | suf;
if(lst == 0) continue;
else q[x].ans ^= (buc[suf] ^ pre[min(j, lst + len - 1)] ^ pre[lst + len - 1]) << i;
}
}
}
for(int i = 1; i <= Q; ++i)
if(q[i].ans) putchar('A');
else putchar('B');
puts("");
return 0;
}
标签:10,ch,int,CF1511G,isdigit,include,Chips,Board
From: https://www.cnblogs.com/DCH233/p/17100384.html