[清华集训2014]玛里苟斯

因为\(Ans<=2^{63}\)所以根据不同的\(k\)值,所有数的位数\(m\)是不一样的,\(k\)越大,\(m\)越小。

\(Ans=\sum_{i_1=1}^m\sum_{i_2=1}^m...\sum_{i_k=1}^m(2^{\sum_{j=1}^ki_j}E(\prod_{j=1}^kbit(xor(A\subset S))))\)

那么就很显然了,求出\(k\)位全都为1的概率,再乘上前面一坨鸟不拉屎的东西即可。

那么这个概率应该怎么算呢?

我们先用原来的\(n\)个数构造线性基,那么现在我们只需要用63个数就得到了原来的线性空间。

再从63个数中挑出这\(k\)位构造另一个线性基。

如果这一个新构造的线性基能表示出每一位都为1的数,那么它的概率就是\(\frac{2^{n-cnt}}{2^n}=\frac{1}{2^{cnt}}\)(其中\(cnt\)为线性基中有值的位的个数)

然后,就没有然后了。。。

注意:

  • unsigned long long 坑的很
#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
int n,k,cnt;
ull bit[70],need[70],c[7][7],x;
struct FT{
    ull x;bool be;
    FT operator +(FT b){
        if (be&&b.be) return (FT){x+b.x+1,false};
        return (FT){x+b.x,be|b.be};
    }
} ans;
struct base{
    int n;
    ull b[70];
    void init(int len){
        n=len;
        memset(b,0,sizeof(b));
    }
    void insert(ull x){
        for (int i=n;i>=0&&x;i--)
            if (x>>i&1)
                if (b[i]) x^=b[i];
                else {b[i]=x;break;}
    }
    bool check(ull x){
        ull res=0;
        for (int i=n;i>=0;i--){
            if (!b[i]) continue;
            if ((x>>i&1)^(res>>i&1)) res^=b[i];
        }
        return res==x;
    }
} B,calc;
inline ull read()
{
    ull res=0;bool bo=0; char c;
    while (((c=getchar())<'0'||c>'9')&&c!='-');
    if (c=='-') bo=1; else res=c-48;
    while ((c=getchar())>='0'&&c<='9')
        res=(res<<3)+(res<<1)+(c-48);
    return bo?~res+1:res;
}
void Calc(){
    calc.init(cnt-1);
    for (int i=0;i<=B.n;i++){
        if (!B.b[i]) continue;
        int x=0;
        for (int j=1;j<=cnt;j++)
            x|=(B.b[i]>>bit[j]&1)<<(j-1);
        calc.insert(x);
    }
    if (!calc.check((1<<cnt)-1)) return;
    int power=0,rest=k;
    FT val=(FT){1,0};
    for (int i=1;i<=cnt;i++) power+=bit[i]*need[i];
    for (int i=0;i<=calc.n;i++)
        if (calc.b[i]) power--;
    for (int i=1;i<=cnt;i++) val.x*=c[rest][need[i]],rest-=need[i];
    if (power>=0)
        for (int i=1;i<=power;i++) val.x<<=1;
    else
        for (int i=1;i<=-power;i++){
            if (val.x&1) val.be=true;
            val.x>>=1;
        }
    ans=ans+val;
}
void dfs(int now,int rest){
    if (now==B.n+1){
        if (k==rest) Calc();
        return;
    }
    for (int i=0;i<=k-rest;i++){
        if (i) bit[++cnt]=now,need[cnt]=i;
        dfs(now+1,rest+i);
        if (i) --cnt;
    }
}
int main(){
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++){
        x=read();
        for (int j=63;j>=0;j--)
            if (x>>j&1) {B.n=max(B.n,j);break;}
        B.insert(x);
    }
    for (int i=0;i<=k;i++) c[i][0]=1;
    for (int i=1;i<=k;i++)
        for (int j=1;j<=i;j++)
            c[i][j]=c[i-1][j]+c[i-1][j-1];
    dfs(0,0);
    cout<<ans.x;
    if (ans.be) puts(".5"); else puts("");
    return 0;
}

转载于:https://www.cnblogs.com/WR-Eternity/p/10853645.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值