CF1511G Chips on a Board

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;
}
posted @ 2023-02-08 07:16  DCH233  阅读(21)  评论(0编辑  收藏  举报