1. 程式人生 > >[FMT 莫比烏斯變換 子集和變換] BZOJ 4036 [HAOI2015]按位或

[FMT 莫比烏斯變換 子集和變換] BZOJ 4036 [HAOI2015]按位或

vfk的論文題 看過組合數學 這個習稱子集和變換的東西好像叫莫比烏斯變換? 那麼這種變換就叫快速莫比烏斯變換 FMT? 大霧
開始推柿子
U表示全集 2n1
fi,S 表示 i 秒當前集合為 S 的概率
gi,S為其莫比烏斯變換 gi,S=xSfi,x
這樣 gi,S=(g1,S)i 很好求 也很方便可以搞出其反變換

fi,S=xS(1)|S||x|gi,x
那麼
Ans=======i=01fi,Ui=0fi,Ui=0xU(1)|U||x|gi,xxU(1)|U||x|i=0gi,xxU(1)|U|
|x|
i=0(g1,x)i
xU,xU(1)|U||x|i=0(g1,x)ixU,xU(1)|U||x|1g1,x1

注意判無解

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

const int N=2000005;

int n,m,cnt[N];
double p[N];

int main(){
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  scanf
("%d",&n); m=1<<n; for (int i=0;i<m;i++) scanf("%lf",p+i); for (int i=0;i<n;i++) for (int j=0;j<m;j++) if (j>>i&1) p[j]+=p[j^(1<<i)],cnt[j]++; for (int i=0;i<m-1;i++) if (p[i]>=1-1e-8) return printf("INF\n"),0; double Ans=0; for (int
i=0;i<m-1;i++) if ((n-cnt[i])&1) Ans-=1/(p[i]-1); else Ans+=1/(p[i]-1); printf("%.10lf\n",Ans); return 0; }