zoukankan      html  css  js  c++  java
  • 【bzoj3811】【清华集训2014】玛里苟斯

    3811: 玛里苟斯

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 500  Solved: 196
    [Submit][Status][Discuss]

    Description

    魔法之龙玛里苟斯最近在为加基森拍卖师的削弱而感到伤心,于是他想了一道数学题。
    S 是一个可重集合,S={a1,a2,…,an}。
    等概率随机取 S 的一个子集 A={ai1,…,aim}。
    计算出 A 中所有元素异或 x, 求 xk 的期望。
     

     

    Input

    第一行两个正整数 n, k。
    以下 n 行每行一个整数,表示 ai。
     

     

    Output

    如果结果是整数,直接输出。如果结果是小数(显然这个小数是有限的),输出精确值(末尾不加多余的 0)。
     

     

    Sample Input

    4 2

    0

    1

    2

    3

    Sample Output

    3.5

    HINT

     

    限制与约定

    1≤n≤100000,1≤k≤5,ai≥0。最终答案小于 2^63 。k=1,2,3,4,5 各自占用 20% 的数据

     

     

    Source

    [Submit][Status][Discuss]

    题解:
            wwwwodddd   ORZ

           求子集异或和k次方的期望;

           首先这和期望的k次方不一样,所以还是老老实实按k分类讨论,按位算贡献吧:
           k=1 , 考虑第i位是否有1,有会贡献的$2^{i-1} $, 全部或起来除二;

           k=2,如果某个异或和的第i位和第j为都有值,会贡献$2^{i+j}$的答案 , 首先这两位都必须要有至少一个1;

                   紧接着如果对于每一个数来说,这两位的值都相同 ,说明两位不相互独立,所以概率是1/2,期望是$2^{i+j-1}$;

                   否则说明两位独立,在异或运算下(0,0)(0,1)(1,0)(1,1)的概率相同为1/4,期望是$2^{i+j-2}$;

           k>=3 , 由于答案在2^63次方以内,所以线性基的大小不会超过22,直接暴力枚举计算期望;

           这题有一个结论是答案*2一定是整数;

          也就是答案的小数最多有一位;

          

    这里有个评论证明了,但是我没太看懂:
    
    https://blog.sengxian.com/solutions/bzoj-3811
    
    自己给出一个可能不太严谨的证明吧(没学过数学。。。):
    
    可以仔细分析一下k==2时的算法;
    再扩展到k次方,发现在异或运算下:
    二进制位之间贡献不相互独立是具有传递性的;
    假设一次计算答案时选定的k个二进制位(可能相同分)集合为:
    B  = {b1,b2,...bk}
    我们可以把他们进一步分成m个集合:
    S1...Sm
    相同集合元素贡献不互相独立,不同集合贡献互相独立;
    这时对答案期望的贡献应该是2^{b1+b2+...+bk - m}  ;
    而k >= m , 且B里面至少有m个不同的二进制位(即bi!=bj这种);
    所以考虑b1+b2+...+bk - m最小的情况:
    分析可以发现最小为-1;
    所以答案小数点后只有一位;
    
    
    
    。。。。。。
    如果你感兴趣的话

           这样就可以用一个数存下对2^|B|的除数和余数,分类讨论小数位的情况(建议看下代码);

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<queue>
     6 #include<cmath>
     7 #include<vector>
     8 #include<stack>
     9 #include<map>
    10 #include<set>
    11 #define Run(i,l,r) for(int i=l;i<=r;i++)
    12 #define Don(i,l,r) for(int i=l;i>=r;i--)
    13 #define ll unsigned long long
    14 #define ld long double
    15 #define inf 0x3f3f3f3f
    16 using namespace std;
    17 const int N=100010;
    18 int n,m,cnt; 
    19 ll a[N],d[100],res,ans;
    20 char gc(){
    21     static char*p1,*p2,s[1000000];
    22     if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
    23     return(p1==p2)?EOF:*p1++;
    24 }
    25 ll rd(){
    26     ll x=0; char c=gc();
    27     while(c<'0'||c>'9')c=gc();
    28     while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc();
    29     return x;
    30 }
    31 void solve1(){
    32     Run(i,1,n){
    33         ll x=rd(); 
    34         ans|=x;
    35     } 
    36     printf("%llu",ans>>1);
    37     if(ans&1)printf(".5
    ");
    38     else puts("");
    39 } 
    40 void solve2(){
    41     Run(i,1,n)a[i]=rd();
    42     for(int i=0;i<=32;i++)
    43     for(int j=0;j<=32;j++){
    44         int fg1=0,fg2=0,fg3=0;
    45         for(int k=1;k<=n;k++){
    46             if(a[k]>>i&1)fg1=1;
    47             if(a[k]>>j&1)fg2=1;
    48             if((a[k]>>i&1)!=(a[k]>>j&1))fg3=1; 
    49             if(fg1&&fg2&&fg3)break;
    50         }
    51         if(!fg1||!fg2)continue;
    52         if(i+j-fg3-1<0)res++;
    53         else ans+=1ull<<(i+j-fg3-1);
    54     }
    55     ans+=res>>1; res&=1;
    56     printf("%llu",ans);
    57     if(res)printf(".5
    ");
    58     else puts("");
    59 }
    60 void solve3(){
    61     for(int i=1;i<=n;i++){
    62         ll x=rd();
    63         for(int j=63;~j;j--)if(x>>j&1){
    64             if(!d[j]){d[j]=x;break;}
    65             else x^=d[j];
    66         }
    67     } 
    68     for(int i=0;i<=63;i++)if(d[i])a[cnt++]=d[i];
    69     for(int i=0;i<1<<cnt;i++){
    70         ll x=0;
    71         for(int j=0;j<cnt;j++)if(i>>j&1)x^=a[j];
    72         ll t1=0,t2=1;
    73         for(int j=1;j<=m;j++){
    74             t1*=x , t2*=x;
    75             t1 += t2 >> cnt , t2 &= (1<<cnt) - 1; 
    76         }
    77         ans += t1 , res += t2;
    78         ans += res >> cnt , res &= (1<<cnt) - 1;
    79     }
    80     printf("%llu",ans);    
    81     if(res)printf(".5
    ");
    82     else printf("
    ");
    83 }
    84 int main(){
    85     freopen("in.in","r",stdin);
    86     freopen("out.out","w",stdout);
    87     n=rd(); m=rd();
    88     if(m==1)solve1();
    89     else if(m==2)solve2();
    90     else solve3();
    91     return 0;
    92 }//by tkys_Austin;
    View Code
  • 相关阅读:
    成功解决vc6.0智能提示消失的BUG
    如何在vc6,vc7,vc8下编译x264
    Visual C++ 操作MS Offfice 控件
    在英文版Visual Studion 2005 professional 中使用 Windows Mobile 2003 SE中文模拟器
    x264 20060731 svn 版的编码移植
    泛型算法:Tips
    05年度EmilMatthew’s Blog文档整理
    常用软件滤波方法及其示例程序
    windows server 2003 配置
    TI C64X 视频处理应用编程重点内容提示
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/9899557.html
Copyright © 2011-2022 走看看