bzoj 3811: 玛里苟斯
3811: 玛里苟斯
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 190 Solved: 95
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
0
1
2
3
Sample Output
首先,对于题目的答案小于263,我们可以看出对于不同的k,ai是不同的:
k=1,ai<263
k=2,ai<232
k=3,ai<221
k=4,ai<216
k=5,ai<213
首先,因此我们依据数据范围,对于不同的ai有不同的解法。
其次,题目要求输出精确的小数,由以下推导我们可以知道,小数最多只有.5,不可能存在.25,.125这样的:
对于求出来了其中一种情况x,他对答案的贡献是xk*p,其中p是该情况出现的概率。
我们以x=2为例,其他k的情况类似:
我们把这个x按二进制分成了最多n位,也就是最大的数的最高位为n。那么他的k次方是(w0*20+w1*21+w2*22……+wn*2n)*(w0*20+w1*21+w2*22……+wn*2n),展开就是w0*w0*20*20+w0*w1*20*21……wn*wn*2n*2n。其中wi是它每个二进制位的值。
对于每个项wi*wj*2i+j,他存在的情况是wi为1且wj为1,也就是该位异或和为1。那么他的存在的概率为P/2N(N为输入的数列数字数),P为该两位皆为1的情况数。
证明题外话:对于数列,我们可以先做个线性基,把线性相关的数字去掉,剩下的都是线性无关的数,这样方便处理。
我们可以构造一个异或(%2)的增广矩阵来求解这样的一个P的数量,x1~xn,即xi代表这个数字是否在集合中,作为一个行向量X,把所有数字按按二进制位分解,每个数字占一列,构造一个矩阵MART.
那么我们求解的是X*MART=ANS,ANS为一个行向量,只有你要求的对应位为1,其余为0。
假如我们求解的是i位和j位,我们的矩阵对应方程差不多是这样的:
(2333 此处^为异或)
x1*w(1,0)^x2*w(2,0)^x3*w(3,0) ……^xN*w(N,0) =0;
x1*w(1,1)^x2*w(2,1)^x3*w(3,1) ……^xN*w(N,1) =0;
……
x1*w(1,i)^x2*w(2,i)^x3*w(3,i) ……^xN*w(N,i) =1;
……
x1*w(1,j)^x2*w(2,j)^x3*w(3,j) ……^xN*w(N,j) =1;
……
x1*w(1,n)^x2*w(2,n)^x3*w(3,n) ……^xN*w(N,n) =0;
下面还有N-n个方程,对应更高位。毕竟是个矩阵嘛行数等于列数,但它们的w全为0,等号右边也为0,对求解无影响就不列举了。
其中w(i,j),j代表数列第i个数字的第j位。
我们经过高斯消元以后弄成上三角,可以得出有t个f[i][i]非零的行,那么只有这t个xi是有唯一解的,其他的xi有多解。因为%2,所以其他xi有2解,那么总共就有2N-t个解,即P=2N-t;
那么wi*wj存在的概率为p/2N=1/(2t);
那么每项对答案的贡献为2i+j-t。
对于i≠j,i+j≥1,t≤2,因此最多小数点后1位.5。
对于i==j,上述方程只有一行初始为1,所以t≤1,i+j≥0,也是最多.5。
上述结论扩展成k=n的情况,无非是方程等于1的行增加为n。
如果我们求解的位(wi*wj*wt.....)中有k位不同,那么方程等于1的行就缩小为k行,因此i+j+t....≥0+1+……k-1=k*(k-1)/2>=k-1=t-1,k≥2。
∴Σp-t>=-1,p为所求解对应位的位号。对应k=2的贡献2i+j-t,K=n贡献为2Σp-t>=2-1。所以最多有一位小数.5。
k=1显而易见最多/2所以k=1也是最多也是.5。
至此证明完毕。
接下来我们对应数据范围,提出三种不同范围下的解法:
k=1时,就求x的期望,它是线性的。对于所有数的所有子集的异或和,我们从他们某个二进制位看。如果有数字该位为1,那么该位有奇数个1和偶数个1的概率是相等的,皆为1/2。为奇数个为该位为1的情况,为1/2。如果没有则不可能为1,该位始终为0。
那么我们只要把每个数字或一下,然后乘1/2就是答案了。
k=2时,就要按位做了。先做个线性基剔除线性无关的向量。然后把在线性基每位唯一化(即消消元弄成每位上只有一个数字有1),这样做方便处理独立性。按照上面证明的展开,那么对于两位i,j,由k=1可得,如果这两位独立的话(即不在同一个数字中相应位为1),那么等概率出现(0,0),(0,1),(1,0),(1,1),(1,1)即wi,wj存在的概率为1/4,不独立的话只可能等概率出现(0,0)和(1,1),(1,1)概率为1/2。
那么枚举32位*32位,算算他们均为1的概率P*2i+j,作为答案贡献加入答案中。
k≥3时,由于ai<221 ,即使枚举0~ai也最多百万级别的时间复杂度。我们可以类似线性基求第k小枚举出所有可能出现的数字。于是我们可以考虑做完线性基后,唯一化,构造新数组存不为0的元素中。
然后枚举每个数是否加入异或贡献中,这样可以求出所有数异或的所有值了。借用之前题目的结论,每个不同的异或值有P=2n-|μ|选择元素的方法,n为原本数组个数,|μ|为新构造的数组个数。那么每个值出现的概率就是P/总选择方法数=P/(2n)=1/(2|μ|)的概率,值 乘 概率即为对答案的贡献。
这里需要做个两位的高精来保证数字不出现错误。
1 #include<bits/stdc++.h> 2 #define clr(x) memset(x,0,sizeof(x)) 3 #define clr_1(x) memset(x,-1,sizeof(x)) 4 #define LL unsigned long long 5 #define mod 1000000007 6 using namespace std; 7 const int N=2e5+10; 8 LL a[N],liner[100],per[100]; 9 bool f[40][40]; 10 bool bits[40]; 11 int n,m,k,cnt; 12 LL ans,res,keepbit; 13 void calc(int bit) 14 { 15 clr(liner); 16 LL p; 17 for(int i=1;i<=n;i++) 18 { 19 for(int j=bit;j>=0;j--) 20 { 21 p=a[i]; 22 if(p>>j) 23 { 24 if(liner[j]) p^=liner[j]; 25 else 26 { 27 liner[j]=p; 28 break; 29 } 30 } 31 } 32 } 33 for(int i=bit;i>=0;i--) 34 { 35 for(int j=i-1;j>=0;j--) 36 if((liner[i]>>j)&1) liner[j]^=liner[i]; 37 } 38 cnt=0; 39 for(int i=bit;i>=0;i--) 40 if(liner[i]) 41 per[++cnt]=liner[i]; 42 return ; 43 } 44 void solve1(int n) 45 { 46 ans=0,res=0; 47 for(int i=1;i<=n;i++) 48 ans|=a[i]; 49 if(ans&1) 50 res=1; 51 ans>>=1; 52 return ; 53 } 54 void solve2(int n) 55 { 56 clr(bits); 57 ans=res=0; 58 bool zero; 59 for(int i=32;i>=0;i--) 60 { 61 zero=0; 62 for(int j=1;j<=cnt;j++) 63 { 64 f[i][j]=(per[j]>>i)&1; 65 zero|=f[i][j]; 66 } 67 bits[i]=zero; 68 } 69 int p; 70 for(int i=32;i>=0;i--) 71 for(int j=32;j>=0;j--) 72 if(bits[i]>0 && bits[j]>0) 73 { 74 p=1; 75 for(int l=1;l<=cnt;l++) 76 if(f[i][l]^f[j][l]) 77 { 78 p++; 79 break; 80 } 81 if(i+j-p>=0) 82 ans+=(1LL<<(i+j-p)); 83 else 84 { 85 res++; 86 } 87 ans+=res>>1; 88 res&=1; 89 } 90 return ; 91 } 92 93 void dfs(int pos,LL num) 94 { 95 96 if(pos>cnt) 97 { 98 //两位高精度计算u高位,v低位,因为这东西太大了。k>=3的情况下ans和res也算是一个高精度的高位和低位关系。 99 LL u=0,v=1; 100 for(int i=1;i<=k;i++) 101 { 102 u*=num; 103 v*=num; 104 u+=v>>cnt; 105 v&=keepbit; 106 } 107 ans+=u; 108 res+=v; 109 ans+=res>>cnt; 110 res&=keepbit; 111 return ; 112 } 113 dfs(pos+1,num^per[pos]); 114 dfs(pos+1,num); 115 return ; 116 } 117 void solve3(int n,int k) 118 { 119 ans=0; 120 res=0; 121 keepbit=(1LL<<cnt)-1; 122 dfs(1,0); 123 return ; 124 } 125 int main() 126 { 127 scanf("%d%d",&n,&k); 128 for(int i=1;i<=n;i++) 129 scanf("%llu",&a[i]); 130 if(k==1) 131 solve1(n); 132 else if(k==2) 133 { 134 calc(32); 135 solve2(n); 136 } 137 else 138 { 139 calc(61/k+1); 140 solve3(n,k); 141 } 142 printf("%llu",ans); 143 if(res) printf(".5"); 144 printf("\n"); 145 return 0; 146 }