ABC 172 Unfair Nim题解

这是一个nim游戏,先手必胜的策略也是非常显然的: A 1 x o r A 2 . . . x o r A n ≠ 0 A_1 xorA_2...xorA_n \neq 0 A1xorA2...xorAn=0
这样如果后手必胜则移动后的 A 1 ′ x o r A 2 ′ = A 3 x o r A 4 x o r A 5 . . . A n A'_1 xorA'_2=A_3 xorA_4xorA_5...A_n A1xorA2=A3xorA4xorA5...An
x = A 3 x o r A 4 x o r A 5 . . . A n , A 1 = y , A 2 = z , A 1 ′ = a , A 2 ′ = b x=A_3 xorA_4xorA_5...A_n,A_1=y,A_2=z,A'_1=a,A'_2=b x=A3xorA4xorA5...An,A1=y,A2=z,A1=a,A2=b
所以我们需要找到满足条件的a,b:
a + b = y + z , a x o r b = x , a ≤ y , a > 0 a+b=y+z,a xorb=x,a\leq y,a >0 a+b=y+z,axorb=x,ay,a>0
其中a最小是多少。
由于 a x o r b = a + b − 2 ( a A N D b ) axorb=a+b-2(aANDb) axorb=a+b2(aANDb)
注以下的xor用^表示,and用&表示
所以上面的式子推一下就可以发现:a^b=x=a+b-2(a&b) ⇒ \Rightarrow a&b= a + b − x 2 \frac{a+b-x}{2} 2a+bx,所以如果a+b-x是奇数答案不存在。
如果我们有了a&b的值,则a和b中的某一些位置就固定了下来。由于我们知道a+b的值,所以a和b中剩余(不在a&b中)的位的和等于a+b-2*(a&b)由于不存在进位所以贪心分配就ok了。
code

#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define KEEP while(1)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define debug_pair(A) cerr<<A.FIR<<" "<<A.SEC<<endl;
#define biggest(A,B) A=max(A,B)
#define smallest(A,B) A=min(A,B)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
typedef pair<mp,mp> superpair;
int n;
LL a[303];
int main(){
	fastio;
	cin>>n;
	rb(i,1,n)
		cin>>a[i];
	LL tmp=0;
	// a xor b = a+b - 2*(a and b)
	rb(i,3,n){
		tmp^=a[i];
	}			
	LL need=a[1]+a[2]-tmp;
	if(need<0||need%2==1){
		cout<<"-1"<<endl;
		return 0; 
	}
  LL sum=a[1]+a[2];
	LL rest=a[1]+a[2]-need;
	need/=2;
	LL upp=a[1];
	a[1]=need;
  	a[2]=need;
	rl(i,42,0){
		if(need&(1ll<<i)){
			if(rest&(1ll<<i)) {
				cout<<-1<<endl;
				return 0;
			}
			continue;
		}	
		if(rest&(1ll<<i)){
			if(a[1]+(1ll<<i)<=upp){
				a[1]+=1ll<<i;
			}
          	else{
            	a[2]+=1ll<<i;
            }
		}
	}
	if(a[1]==0||a[2]>=sum||a[1]>upp){
		cout<<-1<<endl;
		return 0;
	}
	cout<<upp-a[1]<<endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值