【BZOJ4036】[HAOI2015]按位或 FWT
阿新 • • 發佈:2018-03-18
pre get 一個數 script blog 通過 content cal bsp
0.25 0.25 0.25 0.25
【BZOJ4036】[HAOI2015]按位或
Description
剛開始你有一個數字0,每一秒鐘你會隨機選擇一個[0,2^n-1]的數字,與你手上的數字進行或(c++,c的|,pascal的or)操作。選擇數字i的概率是p[i]。保證0<=p[i]<=1,Σp[i]=1問期望多少秒後,你手上的數字變成2^n-1。Input
第一行輸入n表示n個元素,第二行輸入2^n個數,第i個數表示選到i-1的概率
Output
僅輸出一個數表示答案,絕對誤差或相對誤差不超過1e-6即可算通過。如果無解則要輸出INF
Sample Input
20.25 0.25 0.25 0.25
Sample Output
2.6666666667HINT
對於100%的數據,n<=20
題解:先判無解。然後進行fwt。對於每一項p,一次操作變成p的概率是$p$,兩次是$p^2$,三次是$p^3$...所以期望次數就是$p\over (p-1)$。特別地,$2^n-1$的p=1,因為它不需要操作所以次數為0。再fwt回去即可。
手寫小數讀入優化炸精度調了半個小時~再也不寫小數讀入優化了~
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef double db; const int maxn=(1<<20)+4; const db eps=1e-7; db f[maxn],g[maxn]; bool vis[30]; int n; db rd() { db ret=0,tmp=0.1; char gc=getchar(); while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+gc-‘0‘,gc=getchar(); if(gc==‘.‘) { gc=getchar(); while(gc>=‘0‘&&gc<=‘9‘) ret=ret+(gc-‘0‘)*tmp,tmp/=10,gc=getchar(); } return ret; } inline void fwt(db *a) { int i,h; for(h=0;h<n;h++) for(i=0;i<(1<<n);i++) if((i>>h)&1) a[i]+=a[i^(1<<h)]; } inline void ufwt(db *a) { int i,h; for(h=0;h<n;h++) for(i=0;i<(1<<n);i++) if((i>>h)&1) a[i]-=a[i^(1<<h)]; } int main() { n=rd(); int i,j; for(i=0;i<(1<<n);i++) { scanf("%lf",&f[i]); if(f[i]>0) for(j=0;j<n;j++) if((i>>j)&1) vis[j]=1; } for(j=0;j<n;j++) if(!vis[j]) { puts("INF"); return 0; } fwt(f); for(i=0;i<(1<<n);i++) { if(i==(1<<n)-1) f[i]=0; else f[i]=f[i]/(f[i]-1); } ufwt(f); printf("%.10lf",f[(1<<n)-1]+1); return 0; }//2 0.25 0.25 0.25 0.25
【BZOJ4036】[HAOI2015]按位或 FWT