AtCoder Beginner Contest 172.F - Unfair Nim

AtCoder Beginner Contest 172.F - Unfair Nim

傳送門

思路:異或的性質+構造。

顯然題目背景是NimNim遊戲,我們目的是讓後手勝,顯然nn堆石子異或爲00時,後手必勝。接下我們需要構造來使nn堆石子異或和爲00

因爲題目要求我們只能將移動第一堆石子給第二堆石子。

我們記第一堆和第二堆石子個數分別爲a,ba,b

所以我們可以預處理第33堆到第nn堆石子的異或和,我們記爲cc

設需要移動的石子數爲xx個。

即我們要使:(ax)(b+x)c=0(ax)(b+x)=c(a-x)\oplus(b+x)\oplus c=0\rightarrow (a-x)\oplus (b+x)=c

首先我們需要知道幾個結論:

1:a1a2ani=1naia_1\oplus a_2\dots \oplus a_n\leq \sum\limits_{i=1}^n a_i

nn個數異或和不能大於其求和。顯然取等當這個nn個數兩兩的11所在位不同。

2.異或和與求和奇偶性相同。

3.要構造長度爲2的數組。

最開始滿足的條件是zzx=0,z=yx2xyz\oplus z\oplus x=0,z=\dfrac{y-x}{2},x是異或和,y是求和。

當且僅當(z&x)==0(z\&x)==0,長度才能變爲2。即z,xz,x兩個數1的位完全不同,因此才能滿足zx=z+xz\oplus x=z+x.

以上證明如果不懂可以看看之前的博客寫的一個類似的題,相信會有更清楚的理解。
博客鏈接

因此我們可以先排除一些不可能的答案。

s=a+b,d=(sc),ans=d/2s=a+b,d=(s-c),ans=d/2

((d&1)(d<0)(ans>a)(ans&c))((d\&1)||(d<0)||(ans>a)||(ans\&c)) 是不可能的情況。

第一個對應性質2,第二個對應性質1,第三個是要當前最小的構造zz必須不能大於aa

第四個是性質3.

因爲題目是要求拿走的石子數最少,即ansans要在a\leq a的情況下最大。

因爲ans,(ansc)ans,(ans\oplus c)前一個數的11所在位,後面全部有,且ans,cans,c的1位不同。(性質3)

所以我們只需要從cc裏拿11過來給前面一個數,讓ansans變大。

所以枚舉一下cc的1的位就解決了此題。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first 
#define se second
int main(){
	int n;
	ll a,b,c=0;
	scanf("%d%lld%lld",&n,&a,&b);
	for(int i=3;i<=n;i++){
		ll x;
		scanf("%lld",&x);
		c^=x;
	} 	
	ll s=a+b,d=(s-c),ans=d/2;
	if((d&1)||d<0||ans>a||(ans&c)) return puts("-1"),0;
	for(ll i=(1LL<<61);i;i>>=1){
		if((i&c)&&ans+i<=a) ans+=i; 
	}
	printf(ans?"%lld\n":"-1\n",a-ans);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章