UOJ#36. 【清華集訓2014】瑪裏茍斯 線性基
阿新 • • 發佈:2019-02-08
end pow 分類討論 概率 異或和 etc turn using += $k\leq 3$ : 由於答案不超過 $2^{63}$ ,直接把線性基搞出來之後暴力枚舉就好了。
原文鏈接https://www.cnblogs.com/zhouzhendong/p/UOJ36.html
題解
按照 $k$ 分類討論:
k=1 : 我們考慮每一位的貢獻。若有至少一個數第 $i$ 位為 $1$ ,則對答案的貢獻為 $2^i/2$ 。
k=2 : 發現每個異或和的平方為 $\sum_i\sum_j2^{i+j}bit_ibit_j$。那麽考慮第 $i$ 位和第 $j$ 位的積的期望值。如果所有的數中,第 $i$ 位和第 $j$ 位均相等且非全零,那麽參考 k=1 的情況,期望為 1/2;否則,第 $i$ 位為 $1$ 的概率為 1/2,第 $j$ 位為 $1$ 的概率為 1/2,$i×j$ 為 $1$ 的概率為 0.25 。
代碼
#include <bits/stdc++.h> #define clr(x) memset(x,0,sizeof (x)) using namespace std; typedef long long LL; typedef unsigned long long ULL; LL read(){ LL x=0,f=0; char ch=getchar(); while (!isdigit(ch)) f|=ch==‘-‘,ch=getchar(); while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return f?-x:x; } const int N=100005; int n,k; ULL a[N]; void init(){ static ULL x[64]; clr(x); n=read(),k=read(); for (int i=1;i<=n;i++){ ULL v=read(); for (int i=63;~i;i--) if (v>>i&1ULL) if (!x[i]){ x[i]=v; break; } else v^=x[i]; } n=0; for (int i=63;~i;i--) if (x[i]) a[++n]=x[i]; } void Out(ULL x){ cout<<x/2; if (x&1LLU) cout<<".5"; } namespace k1{ void solve(){ ULL ans=0; for (int i=1;i<=n;i++) ans|=a[i]; Out(ans); } } namespace k2{ void solve(){ ULL ans=0; for (int i=0;i<33;i++) for (int j=0;j<33;j++){ int f1=0,f2=0,f=0; for (int t=1;t<=n;t++){ f1|=a[t]>>i&1ULL; f2|=a[t]>>j&1ULL; f|=(a[t]>>i&1ULL)!=(a[t]>>j&1ULL); } if (!f1||!f2) continue; ans+=1ULL<<(i+j-f); } Out(ans); } } namespace k3{ __int128 tot; __int128 Pow(__int128 x,int y){ __int128 ans=1; for (;y;y>>=1,x*=x) if (y&1) ans*=x; return ans; } void solve(){ tot=0; for (int i=(1<<n)-1;i>=0;i--){ ULL tmp=0; for (int j=0;j<n;j++) if (i>>j&1) tmp^=a[j+1]; tot+=Pow(tmp,k); } while (tot%2==0&&n>1) n--,tot/=2; cout<<(ULL)tot/2; if (tot%2==1) cout<<".5"; } } int main(){ init(); if (k==1) k1::solve(); else if (k==2) k2::solve(); else k3::solve(); return 0; }
UOJ#36. 【清華集訓2014】瑪裏茍斯 線性基