[CQOI2013] 新Nim游戏

新Nim游戏

题解

Nim游戏,规则大家应该都清楚,反正就是:

甲,乙两个人玩 Nim 取石子游戏。

Nim 游戏的规则是这样的:地上有 nn 堆石子(每堆石子数量小于 10^4104),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取完,不能不取。每次只能从一堆里取。最后没石子可取的人就输了。假如甲是先手,且告诉你这 nn 堆石子的数量,他想知道是否存在先手必胜的策略。

如果要先手胜利的话,后手就得无论拿那几堆都得不到一个异或为0的情况。这可以用线性基来处理。

插入线性基时,若x已经能够构造出来了,那么就会出现异或和为0的情况,这个x就必须拿走。如此先手就必胜了,接下来我们要考虑如何让取走的数量最小。

很容易发现,如果从大到小来插入,将已经构造出来的取走就是最优的。

证明也很容易。

从大到小的话,若它不能插,则满足它插条件的已经被插的一定比它大,由于异或不会进位,显然让它被取走一定比取走其它的更优。

至于更严谨的证明可参照https://blog.csdn.net/Jaihk662/article/details/75050313,写得好呀。

源码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define MAXN 100010
typedef long long LL;
#define int LL
typedef pair<int,int> pii;
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
int n,a[105],d[105],ans;
bool insert(int x){
	for(int i=30;i>=0;i--)
		if((x>>i)&1){
			if(d[i])x^=d[i];
			else{d[i]=x;break;};
		}
	return x;
}
signed main(){
	read(n);
	for(int i=1;i<=n;i++)read(a[i]);
	sort(a+1,a+n+1);
	for(int i=n;i>0;i--)if(!insert(a[i]))ans+=a[i];
	printf("%lld\n",ans);
	return 0;
}

谢谢!!!

原创文章 123 获赞 166 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Tan_tan_tann/article/details/106086157