bzoj3811 玛里苟斯

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% 的数据

 

正解:$dp$+线性基。

$k=1$比较简单,考虑把单独计算每一位。

如果有至少一个数这一位是$1$,那么很显然,这一位为$0$和为$1$的概率相等,都是$0.5$;否则这一位只可能是$0$。

$k=2$其实差不多,但是我还是没想到。。

考虑枚举异或以后的数的二进制任意两位的平方,当这两位的平方有贡献当且仅当这两位都是$1$。

然后计算一下这两位都是$1$的概率,假设两位分别为$i,j$,那么这两位组合的期望就是$2^{i+j}*p$。

$p$也比较好算,如果所有数在$i$和$j$两位都相等的话那么概率就是$0.5$,否则概率就是$0.25$。

$k>=3$时,因为题目说答案小于$2^{63}$,那么每个数肯定最多只有$22$位。

根据线性基的性质,$n$个数异或以后的数出现概率与线性基中这个数出现概率相同。

假设线性基元素有$k$个,那么$n$个数异或以后每个数出现概率就是$\frac{1}{2^{k}}$,于是我们直接写一个爆搜,搜出线性基的所有异或情况就行了。

 

  1 #include <bits/stdc++.h>
  2 #define il inline
  3 #define RG register
  4 #define ull unsigned long long
  5  
  6 using namespace std;
  7  
  8 ull a[100010];
  9 int n,k;
 10  
 11 il ull gi(){
 12   RG ull x=0,q=1; RG char ch=getchar();
 13   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
 14   if (ch=='-') q=-1,ch=getchar();
 15   while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
 16   return q*x;
 17 }
 18  
 19 namespace solve1{
 20    
 21   ull ans;
 22    
 23   int main(){
 24     for (RG int i=1;i<=n;++i) ans|=a[i];
 25     printf("%llu",ans>>1);
 26     puts((ans&1)?".5":"");
 27     return 0;
 28   }
 29    
 30 }
 31  
 32 namespace solve2{
 33    
 34   ull ret,res,ans;
 35    
 36   int main(){
 37     for (RG int i=1;i<=n;++i) ret|=a[i];
 38     for (RG int i=0;i<32;++i)
 39       for (RG int j=0,fg=0;j<32;++j,fg=0)
 40     if ((ret>>i&1) && (ret>>j&1)){
 41       for (RG int p=1;p<=n;++p)
 42         if ((a[p]>>i&1)^(a[p]>>j&1)){ fg=1; break; }
 43       if (i+j-1-fg<0) ++res; else ans+=1llu<<(i+j-1-fg);
 44     }
 45     ans+=res>>1,printf("%llu",ans);
 46     puts((res&1)?".5":""); return 0;
 47   }
 48    
 49 }
 50  
 51 namespace solve3{
 52    
 53   ull p[30],tot,ans,rhl;
 54   int Sz;
 55    
 56   il ull qpow(RG ull a,RG int b){
 57     RG ull ans=1;
 58     while (b){
 59       if (b&1) ans*=a; a*=a,b>>=1;
 60     }
 61     return ans;
 62   }
 63    
 64   il void insert(RG ull x){
 65     for (RG int i=Sz;i>=0;--i){
 66       if (!(x>>i&1)) continue;
 67       if (!p[i]){ p[i]=x; break; }
 68       x^=p[i];
 69     }
 70     return;
 71   }
 72    
 73   il void dfs(RG int x,RG ull S){
 74     if (x>Sz){
 75       RG ull res=1;
 76       for (RG int i=1;i<k;++i) res*=S;
 77       if (res<rhl){
 78     res*=S,tot+=res;
 79     if (tot>=rhl) ans+=tot/rhl,tot%=rhl;
 80       } else{
 81     ans+=res/rhl*S,res%=rhl,res*=S,tot+=res;
 82     if (tot>=rhl) ans+=tot/rhl,tot%=rhl;
 83       }
 84       return;
 85     }
 86     dfs(x+1,S),dfs(x+1,S^p[x]); return;
 87   }
 88    
 89   int main(){
 90     if (k==3) Sz=21; if (k==4) Sz=15; if (k==5) Sz=12;
 91     for (RG int i=1;i<=n;++i) insert(a[i]);
 92     rhl=1<<(Sz+1),dfs(0,0),printf("%llu",ans);
 93     puts(tot?".5":""); return 0;
 94   }
 95    
 96 }
 97  
 98 int main(){
 99 #ifndef ONLINE_JUDGE
100   freopen("maligous.in","r",stdin);
101   freopen("maligous.out","w",stdout);
102 #endif
103   n=gi(),k=gi();
104   for (RG int i=1;i<=n;++i) a[i]=gi();
105   if (k==1) solve1::main();
106   if (k==2) solve2::main();
107   if (k>=3) solve3::main();
108   return 0;
109 }

 

posted @ 2017-09-12 17:20  wfj_2048  阅读(513)  评论(0编辑  收藏  举报