Codeforces - 662A Gambling Nim
题意:
n张卡牌,正反两面有两个数字。每一面的概率都为0.5。将所有卡片的值异或起来,求异或值不为0的概率。
题解:
考虑异或值为0的情况。
用sum表示a[1]^...^a[n]的值。用c[i]表示a[i]^b[i]。那么sum^c[i]^...^c[j]代表总的异或值。即sum=c[i]^...^c[j]时,他们的异或值为0。
那么问题就变成求c的子集,使得子集内的所有值异或和为sum。
求出c[1]~c[n]的线性基,用bit数组表示。
对于sum,若他不能用线性基表示,即总的异或和恒不为0,答案就为1/1。
如果能用线性基表示,所有异或和为sum的情况数就为2n-tot(tot为线性基的大小)。异或和为0的概率为2n-tot/2n = 1/2tot。
那么异或和不为0的概率为(2tot-1)/2tot。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 5e5+10; int n; int tot; ll b, sum; ll a, bit[65]; void add(ll *a, ll b) { for(int i = 62; i >= 0; i--) if((1ll<<i)&b) { if(a[i]) b ^= a[i]; else { a[i] = b; tot++; return ; } } } int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%lld%lld", &a, &b); sum ^= a; add(bit, a^b); } int cnt; for(int i = 62; i >= 0; i--) if((1ll<<i)&sum) { sum ^= bit[i]; cnt++; } if(sum) { puts("1/1"); return 0; } ll ans = 1ll<<tot; printf("%lld/%lld\n", ans-1, ans); }