博弈 bzoj 4035 HAOI2015 数组游戏

https://www.lydsy.com/JudgeOnline/problem.php?id=4035

考虑如果选择的限定不是白子,也可以选择黑子

容易发现和原先游戏是等价的(可以撤销别人的操作

此时对于每一个白子的贡献是独立的

可得\(sg[]\)

\[sg[x] = mex_{k=1}^{n/x}\left \{ sg[x] \;xor \;sg[2x] \;xor \;\dots \;sg[kx]\right \}\]

然后打表发现对于\(n/x\)相同的数

sg值是相同的

然后复杂度就是\(\mathcal O(\sqrt n \times \sqrt n) = \mathcal O(n)\) 听说常数很小

为什么我的写法有8倍常数啊

后来学习了一下fyy的写法开ofast过了...

%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
#include <bits/stdc++.h>
#define fo(i, n) for(int i = 1; i <= (n); i ++)
#define out(x) cerr << #x << " = " << x << "\n"
#define type(x) __typeof((x).begin())
#define foreach(it, x) for(type(x) it = (x).begin(); it != (x).end(); ++ it)
  using namespace std;
// by piano
template<typename tp> inline void read(tp &x) {
  x = 0;char c = getchar(); bool f = 0;
  for(; c < '0' || c > '9'; f |= (c == '-'), c = getchar());
  for(; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
  if(f) x = -x;
}
const int N = 3e5 + 233;
int vis[N];
int used[N], used_cnt = 0;
int st[N], up[N], top = 0, dp[2][N];
int n, T, K, m, q;

inline int getnum(int i, int j, int x) {
  return up[j] / x - up[i] / x;
}

inline int cal(int x) {
  return x > K ? dp[1][n / x] : dp[0][x];
}

inline void doit(void) {
  for(int i = 1, last = 0; i <= n; i = last + 1) {
    last = n / (n / i);
    st[++ top] = i; up[top] = last;
  }
  K = sqrt(n);
  for(int i = top; i >= 1; i --) {
    int x = st[i];
    used_cnt = 0;
    vis[0] = 1; used[++ used_cnt] = 0;
    int p = 0;
    for(int j = x + x; j <= n; ) {
      int xk = j;
      int _t = n / (n / xk) / x * x;
      int num = (_t - j) / x + 1;;
      if(!num) continue;
      int t = p ^ cal(xk);
      
      // if(i == 1) cout << p << " " << t << " " << num << " " << j << "\n";
      vis[t] = 1; used[++ used_cnt] = t;
      if(num & 1) p = t;
      j = _t + x;
    }
    int t = 0;
    while(vis[t]) ++ t;
    if(x > K) dp[1][n / x] = t;
    else dp[0][x] = t;
    for(int k = 1; k <= used_cnt; k ++)
      vis[used[k]] = 0;
  }
}

int sg[N];
inline void n2(void) {
  for(int i = n; i >= 1; i --) {
    memset(vis, 0, sizeof vis);
    int t = 0;
    for(int j = i; j <= n; j += i) {
      vis[t ^= sg[j]] = 1;
    }
    t = 0;
    while(vis[t]) ++ t;
    sg[i] = t;
  }
  for(int i = 1; i <= n; i ++)
    cout << sg[i] << " "; puts("");
}

main(void) {
  read(n);
  // n2();
  doit();
  // for(int i = 1; i <= n; i ++)
  //   cout << cal(i) << " "; puts("");
  for(read(T); T --;) {
    read(q);
    int ans = 0;
    for(int i = 1; i <= q; i ++) {
      int x; read(x); ans ^= cal(x);
    }
    puts(!ans ? "No" : "Yes");
  }
}

猜你喜欢

转载自www.cnblogs.com/foreverpiano/p/9244813.html