[HAOI2015] 按位或

传送门
BZOJ怎么挂掉了。。

因为这题有点东西,所以单开一篇。。

min-max容斥:

\[min(S)=\sum_{T \subseteq S} (-1)^{|T|-1}min(T) \]

这东西在期望意义下也成立 -_-!

回到这题,全部变成 1 的时间就是每个位变成 1 的时间取max,但这东西还是不好求。
但是一个集合最早有 1 的时间还是可求的。。

对于一个集合 \(T\),设它的状态是 \(mask\) ,一次操作与它有交的概率就是 $$\sum_{i & mask \ne 0} p[i]$$

\(C=((1<<n)-1) \oplus mask\),即 \(mask\) 的补集,上面的柿子就等于 $$1-\sum_{i & C=i} p[i]$$

这个东西呢,似乎可以FWT也可以FMT,然而我都不会QAQ

前几天get到一个叫SOS-DP的东西,也可以做。然后一交发现MLE了!!囧TZ
改成滚动数组就过了QAQ

网上有人说FWT和SOS-DP是一样的,总之我现在对FWT & FMT & SOS-DP这三种东西是懵逼的……

#include<bits/stdc++.h>
#define LL long long
#define fr(i,x,y) for(int i=(x);i<=(y);i++)
#define rf(i,x,y) for(int i=(x);i>=(y);i--)
#define frl(i,x,y) for(int i=(x);i<(y);i++)
using namespace std;
const int N=21;
int n;
double p[1<<N],dp[2][1<<N];

void read(int &x){
	char ch=getchar();x=0;
	for(;ch<'0'||ch>'9';ch=getchar());
	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
}

int main(){
	read(n);
	int all=0;
	frl(i,0,1<<n){
		scanf("%lf",&p[i]);
		if (p[i]!=0) all|=i;
	}
	if (all!=(1<<n)-1) return puts("INF"),0;
	int cur=0;frl(i,0,1<<n) dp[0][i]=p[i];
	fr(j,1,n){
		cur^=1;
		frl(i,0,1<<n)
		 if (i&(1<<j-1)) dp[cur][i]=dp[cur^1][i]+dp[cur^1][i^(1<<j-1)];
		  else dp[cur][i]=dp[cur^1][i];
		//printf("%.6lf ",dp[i][n]);
	}
	//cout<<endl;
	double ans=0;
	frl(i,1,1<<n){
		int T=0;
		frl(j,0,n) if (i&(1<<j)) T++;
		if (T&1) ans+=1.0/(1-dp[cur][all^i]);
		 else ans-=1.0/(1-dp[cur][all^i]);
	}
	printf("%.8lf\n",ans);
	return 0;
}
posted @ 2019-10-03 13:15  ymzqwq  阅读(96)  评论(0编辑  收藏  举报