1. 程式人生 > >【bzoj3811】【清華集訓2014】瑪裡苟斯

【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

2015年國家集訓隊測試

[ 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一定是整數;

       可以用一個數存下對2^|B|的除數和餘數;

       https://blog.sengxian.com/solutions/bzoj-3811 

       證明如下: 
       首先k=1,2時顯然成立。 
       當k>2時: 
      設線性基最多有BASE位。 
      對於每一位,若該位全為0,顯然不會對小數部分產生貢獻。 
      若該位為1,因為子集列舉,所以該位的1會被統計2^BASE/2次。 
      對於每一位均是如此,因此我們只需要考慮進位即可。 
      顯然低位的1會被傳遞到BASE-1位才不能進位(2的整數冪次),即最高位,而分母部分是2^BASE,因此最多會對一個小數位產生影響。

      //我只改了一個字
這是某位大佬的評論的對性質的證明
 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\n");
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\n");
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\n");
82     else printf("\n");
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