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;
}

转载于:https://www.cnblogs.com/y-clever/p/8513279.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值