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);
} 
View Code

 

转载于:https://www.cnblogs.com/Pneuis/p/9090955.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值