BZOJ3105 [cqoi2013]新Nim游戏

Description

\(k\)堆石子,两个人游戏:

  • 首先,A拿走若干堆石子(不能全部拿走)

  • 之后,B拿走若干堆石子(不能全部拿走)

  • 然后从A开始\(Nim\)游戏。

问A能不能取胜。如果能,A第一步至少要拿走多少石子?

Solution

显然可以取胜。A拿的只剩1堆,B不能拿走,A全拿完,B输了。

考虑A第一次拿完之后,剩下的石子在异或意义下必须线性无关。否则B找出一组石子异或为0,A就输掉了。

那么A拿走的石子尽量少等价于剩下的石子尽量多。

也就是求最大权线性无关组,权值即为石子个数。

线性无关组是一个拟阵(遗传性易证,交换性来说,如果两个线性无关组\(X\)\(Y\)\(|X|<|Y|\),那么\(X\)张成的线性空间有\(|X|\)维,\(Y\)张成的线性空间有\(|Y|\)维,后者中必能选出一个元素加到\(|X|\)中线性无关)。

所以我们从大到小判断每堆石子能不能保留即可。

Code

 
#include <algorithm>
#include <cstdio>
const int K = 105;
int J[32], A[K];
bool mark[K];
bool cmp(int a, int b) { return b < a; }
int main() {
  int k;
  scanf("%d", &k);
  for (int i = 0; i < k; ++i) scanf("%d", &A[i]);
  std::sort(A, A + k, cmp);
  long long ans = 0;
  for (int i = 0, j, l; i < k; ++i) {
    for (l = 31, j = A[i]; ~l; --l)
      if ((j >> l) & 1) {
        if (!J[l]) { J[l] = j; break; }
        else j ^= J[l];
      }
    if (l == -1) ans += A[i];
  }
  printf("%lld\n", ans);
  return 0;
}
posted @ 2018-03-06 11:13  _rqy  阅读(...)  评论(... 编辑 收藏