AtCoder Beginner Contest 172.F - Unfair Nim
思路:異或的性質+構造。
顯然題目背景是遊戲,我們目的是讓後手勝,顯然堆石子異或爲時,後手必勝。接下我們需要構造來使堆石子異或和爲。
因爲題目要求我們只能將移動第一堆石子給第二堆石子。
我們記第一堆和第二堆石子個數分別爲。
所以我們可以預處理第堆到第堆石子的異或和,我們記爲。
設需要移動的石子數爲個。
即我們要使:
首先我們需要知道幾個結論:
1:
即個數異或和不能大於其求和。顯然取等當這個個數兩兩的所在位不同。
2.異或和與求和奇偶性相同。
3.要構造長度爲2的數組。
最開始滿足的條件是
當且僅當,長度才能變爲2。即兩個數1的位完全不同,因此才能滿足.
以上證明如果不懂可以看看之前的博客寫的一個類似的題,相信會有更清楚的理解。
博客鏈接
因此我們可以先排除一些不可能的答案。
記
是不可能的情況。
第一個對應性質2,第二個對應性質1,第三個是要當前最小的構造必須不能大於,
第四個是性質3.
因爲題目是要求拿走的石子數最少,即要在的情況下最大。
因爲前一個數的所在位,後面全部有,且的1位不同。(性質3)
所以我們只需要從裏拿過來給前面一個數,讓變大。
所以枚舉一下的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;
}