2020 CCPC-Wannafly Winter Camp Day2 C
题目
思路
\quad
其实一开始就反应出很像是nim博弈了,nim博弈是
a
1
⨁
a
2
⨁
.
.
.
.
.
.
⨁
a
n
=
0
\ a_1\bigoplus a_2 \bigoplus ...... \bigoplus a_n = 0
a1⨁a2⨁......⨁an=0的时候是先手必败态,那么如果这里要先手必胜,既后手必败,那么只要让后手面对异或为0的状态就行了,那么我们假设
a
1
⨁
a
2
⨁
.
.
.
.
.
.
⨁
a
n
=
x
\ a_1\bigoplus a_2 \bigoplus ...... \bigoplus a_n = x
a1⨁a2⨁......⨁an=x, 我们假设先手取出y个,便让剩下的异或为0,即使得
x
⨁
y
=
0
\ x\bigoplus y = 0
x⨁y=0。
\quad
那么其实只要我们找出,有多少个y,能使得
x
⨁
y
=
0
\ x\bigoplus y = 0
x⨁y=0就行,一开始我就卡在了这里,如果暴力每个去找,那么就会TLE,后来题解说,只要你能找到一个y,使得x的最高位对应的位置y也是1,那么y就肯定是了,因为这样
x
⨁
y
=
0
\ x\bigoplus y = 0
x⨁y=0的最高位就是0,而y的最高位就是1,从而达到
x
⨁
y
<
y
\ x\bigoplus y \lt y
x⨁y<y目标。
\quad
那么我们梳理一下思路
- 得到前缀异或和x
- 记录每一位数字的二进制位(用数组记录)
- 查看x的最高位上是否存在有在这一位为1的石头堆数 a i a_i ai
- 这时候我们就可以保证 x ⨁ a i < a i \ x\bigoplus a_i \lt a_i x⨁ai<ai,我们便可以改变 a i a_i ai的值(拿走一定数量),使得 x ⨁ a i ⨁ a i ‘ = 0 \ x\bigoplus a_i \bigoplus a_i^` = 0 x⨁ai⨁ai‘=0,记录答案。
代码
#include <iostream>
using namespace std;
long long a[999],b[999],n,m,sumn,o,t,p,i,j,ans;
int main()
{
scanf("%lld",&n);
for(i = 1; i <= n; i ++ )
{
scanf("%lld",&m);
p = m;
for(j = 0; p != 0; j ++ )
{
b[j] += p%2;
p = p/2;
}
sumn ^= m;
o = sumn;
t = 0;
while(o != 0)
{
o = o >> 1;
t ++;
}
printf("%lld\n",b[t-1]);
}
}