列表

详情


NC19928. [CQOI2013]新NIM游戏

描述

传统的Nim游戏是这样的:有一些火柴堆,每堆都有若干根火柴(不同堆的火柴数量可以不同)。两个游戏者轮流操作,每次可以选一个火柴堆拿走若干根火柴。可以只拿一根,也可以拿走整堆火柴,但不能同时从超过一堆火柴中拿。拿走最后一根火柴的游戏者胜利。 
本题的游戏稍微有些不同:在第一个回合中,第一个游戏者可以直接拿走若干个整堆的火柴。可以一堆都不拿,但不可以全部拿走。第二回合也一样,第二个游戏者也有这样一次机会。从第三个回合(又轮到第一个游戏者)开始,规则和Nim游戏一样。 如果你先拿,怎样才能保证获胜?如果可以获胜的话,还要让第一回合拿的火柴总数尽量小。  

输入描述

第一行为整数k。即火柴堆数。
第二行包含k个不超过109的正整数,即各堆的火柴个数。  

输出描述

输出第一回合拿的火柴数目的最小值。如果不能保证取胜,输出-1。

示例1

输入:

6
5 5 6 6 5 5

输出:

21

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 5ms, 内存消耗: 504K, 提交时间: 2019-08-09 09:27:18

#include <bits/stdc++.h>
using namespace std;
int const N = 100 + 10;
int const maxbit = 32;
int a[N],p[maxbit],n;
long long ans;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	sort(a+1,a+n+1,greater<int>());
	for(int i=1,j;i<=n;i++){
		int x = a[i];
		for(j=maxbit-1;j>=0;j--){
			if(x & (1<<j)){
				if(p[j] == 0){
					p[j] = x;
					break;
				}else{
					x ^= p[j];
				}
			}
		}
		if(j == -1)	ans += a[i];
	}
	printf("%lld\n",ans);
	return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 3ms, 内存消耗: 600K, 提交时间: 2020-04-30 21:30:11

#include<bits/stdc++.h>
using namespace std;

#define ll long long 

const int N=2e5+100;

int a[N],d[N];
int main()
{
	int n;
	cin>>n;
	ll ans=0;
	for(int i=1;i<=n;i++) cin>>a[i],ans+=a[i];
	sort(a+1,a+1+n,greater<int>()); 
	for(int i=1;i<=n;i++)
	{
		int x=a[i];
		for(int i=30;i>=0;i--)
		{
			if(x>>i&1)
			{
				if(d[i]) x^=d[i];
				else 
				{
					d[i]=x;
					break;
				}
			} 
		}
		if(x) ans-=a[i];
	}
	cout<<ans<<endl;
	return 0;
}

上一题