题目链接:https://atcoder.jp/contests/abc172/tasks/abc172_f
题意:给你 n n n堆石子,每堆石子有 a [ i ] a[i] a[i]个。现在两个人玩游戏,每次可以重一推石子中取走 1 1 1个, 2 2 2个,或者把这一堆石子全部取走。现在在游戏开始之前,你可以将第一堆中的若干( 1 − > a [ 1 ] − 1 1->a[1]-1 1−>a[1]−1)个石子放到第二堆,问你最少放多少个可以保证后手必赢,如果不行的话,输出 − 1 -1 −1。
思路:首先我们知道这是一个
n
i
m
nim
nim游戏,结论就是
a
[
1
]
⨁
a
[
2
]
⨁
a
[
3
]
.
.
.
⨁
a
[
n
]
=
0
a[1] \bigoplus a[2]\bigoplus a[3] ... \bigoplus a[n]=0
a[1]⨁a[2]⨁a[3]...⨁a[n]=0的话,后手必败。所以这一题题意就可以转化成,求解最小的
a
n
s
ans
ans,使得
(
a
[
1
]
−
a
n
s
)
⨁
(
a
[
2
]
+
a
n
s
)
⨁
a
[
3
]
.
.
.
⨁
a
[
n
]
=
0
(a[1]-ans) \bigoplus (a[2]+ans)\bigoplus a[3] ... \bigoplus a[n]=0
(a[1]−ans)⨁(a[2]+ans)⨁a[3]...⨁a[n]=0
那该怎么求呢?
1
e
12
1e12
1e12的数据范围,暴力是不可能的啦…
我们设
A
=
a
[
1
]
−
a
n
s
,
B
=
a
[
2
]
+
a
n
s
A = a[1] - ans,B = a[2] + ans
A=a[1]−ans,B=a[2]+ans,这样我们就可以可以知道
A
⨁
B
=
a
[
3
]
⨁
.
.
.
⨁
a
[
n
]
=
y
A \bigoplus B = a[3] \bigoplus... \bigoplus a[n]=y
A⨁B=a[3]⨁...⨁a[n]=y
A
+
B
=
a
[
1
]
+
a
[
2
]
=
x
A+B = a[1] + a[2] = x
A+B=a[1]+a[2]=x
现在就需要一个非常有用的公式 a + b = a ⨁ b + 2 ( a ⋀ b ) a + b = a \bigoplus b + 2(a \bigwedge b) a+b=a⨁b+2(a⋀b)
这样我们就可以得到
{
A
⨁
B
=
y
A
⋀
B
=
(
x
−
y
)
2
\left\{ \begin{aligned} A \bigoplus B & = & y \\ A \bigwedge B & = & \frac{(x - y)}2 \end{aligned} \right.
⎩⎪⎨⎪⎧A⨁BA⋀B==y2(x−y)
另
x
−
y
2
=
X
,
y
=
Y
\frac{x-y}{2} = X , y = Y
2x−y=X,y=Y(只是为了后续书写看起来舒服点)
这里我们就可以看到
x
>
y
x > y
x>y ||
(
x
−
y
)
(x - y)
(x−y)%
2
!
=
0
2 !=0
2!=0,那可定要输出-1。
我们用
X
i
,
Y
i
,
A
i
,
B
i
X_i,Y_i,A_i,B_i
Xi,Yi,Ai,Bi表示分别表示
X
,
Y
,
A
,
B
X,Y,A,B
X,Y,A,B第
i
i
i位二进制数,现在我们就是要找到
A
<
a
[
1
]
A < a[1]
A<a[1]的最大值,可以看到
A
m
i
n
=
X
A_{min} = X
Amin=X,那我们接下来就看一下
X
i
,
Y
i
X_i,Y_i
Xi,Yi四种情况下
A
A
A的值有啥变化。
X
i
=
1
X_i = 1
Xi=1 &&
Y
i
=
1
Y_i = 1
Yi=1,
A
i
,
B
i
A_i,B_i
Ai,Bi无解,输出-1;
X
i
=
1
X_i = 1
Xi=1 &&
Y
i
=
0
Y_i = 0
Yi=0,
A
i
=
1
,
B
i
=
0
A_i = 1,B_i = 0
Ai=1,Bi=0 ||
A
i
=
0
,
B
i
=
1
A_i = 0,B_i = 1
Ai=0,Bi=1,因为我们要让
A
A
A尽量大,我们就要在
A
+
2
i
−
1
<
a
[
1
]
A + 2^{i-1} < a[1]
A+2i−1<a[1]的情况下让
A
i
=
1
A_i = 1
Ai=1;
X
i
=
0
X_i = 0
Xi=0 &&
Y
i
=
1
Y_i = 1
Yi=1,
A
i
=
1
,
B
i
=
1
A_i = 1,B_i=1
Ai=1,Bi=1,
A
A
A值不变;
X
i
=
0
X_i = 0
Xi=0 &&
Y
i
=
0
Y_i = 0
Yi=0,
A
i
=
0
,
B
i
=
0
A_i=0,B_i=0
Ai=0,Bi=0,
A
A
A值不变;
这样,这道题就可以解出来啦,具体操作详见代码。
AC代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <vector>
#include <cstdio>
#include <string>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
#define pii pair<int,int>
#define sd(x) scanf("%d",&x)
#define slld(x) scanf("%lld",&x)
#define pd(x) printf("%d\n",x)
#define plld(x) printf("%lld\n",x)
#define rep(i,a,b) for(int i = (a) ; i <= (b) ; i++)
#define per(i,a,b) for(int i = (a) ; i >= (b) ; i--)
#define mem(a) memset(a,0,sizeof(a))
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define fast_io ios::sync_with_stdio(false)
const LL mod = 1e9 + 7;
const int maxn = 5e5 + 7;
const int INF = 0x3f3f3f3f;
const double pi = acos(-1.0);
int main() {
#ifndef ONLINE_JUDGE
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
long _begin_time = clock();
#endif
int n;
sd(n);
LL a, b;
slld(a), slld(b);
LL sum = a + b;
LL Xor = 0;
rep(i,3,n) {
LL x;
slld(x);
Xor ^= x;
}
bool flag = false;
if(sum < Xor || (sum - Xor) % 2 != 0) flag = true;
LL And = sum - Xor >> 1;
LL ans = And;
per(i,60,0) {
int xx = ((And >> i) & 1LL);
int yy = ((Xor >> i) & 1LL);
if(xx && yy) {
flag = true;
break;
}
if(!xx && yy && ((ans | (1LL << i)) <= a)) {
ans |= (1LL << i);
}
}
if(!ans || ans > a || flag) puts("-1");
else plld(a-ans);
#ifndef ONLINE_JUDGE
long _end_time = clock();
// cout << "time = " << _end_time - _begin_time << endl;
#endif
return 0;
}