linkkkkk
题意:
Nim游戏,去掉任意堆石子后能否使得先手必输。
思路:
求一个子集,每个式子的状态有取或不取两种,分别设为
1
/
0
1/0
1/0。
列一个方程看异或值为
0
0
0,是否有解。
求异或线性方程组的自由元个数或解的个数。
由于全
0
0
0是一组解,所以看是否有多组解,即自由元个数是否大于
0
0
0
代码:
ll n,m=42;
ll a[110][110],g[110];
int Gauss(int n,int m)//返回自由元个数
{
int r, c;
for(r = 0, c = 0; c < n; c++)
{
int t = -1;
for(int i = r; i < m; i++)
{
if(a[i][c])
{
t = i;
break;
}
}
if(t==-1) continue;
for(int i = c; i < n; i++)///交换
{
swap(a[t][i], a[r][i]);
}
for(int i = r + 1; i < m; i++)
{
if(a[i][c])
for(int j = c; j <n; j++)
{
a[i][j] = a[i][j] ^ a[r][j];
}
}
r++;
}
return n-r;
/*if(r < n)
{
for(int i = r; i < n; i++)
{
if(a[i][n]) return 2;
}
return 1;
}
for(int i = n - 1; i >= 0; i--)
{
for(int j = i + 1; j < n; j++)
{
if(a[i][j])
a[i][n] ^= a[j][n];
}
}
return 0;*/
}
void solve()
{
cin >> n;
for(int i=0;i<n;i++) cin>>g[i];
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
a[i][j]=(g[j]>>i)&1;
int ans=Gauss(n,m);
if(ans>0) puts("Yes");
else puts("No");
}
int main()
{
int _;cin>>_;
while(_--) solve();
return 0;
}