luogu3343 [ZJOI2015]地震后的幻想乡

ref
前置技能是bzoj的串珠子。这种子集dp好神啊qwq。
还有这种钦定点转移子集的方法建议按这题的方法写,不要看串珠子qwq

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
int n, m, w[15], uu, vv, siz[1105], cnt[1105];
ll c[55][55];
double f[1105][55], g[1105][55];
int main(){
	cin>>n>>m;
	for(int i=1; i<=m; i++){
		scanf("%d %d", &uu, &vv);
		uu--; vv--;
		w[uu] |= 1<<vv;
		w[vv] |= 1<<uu;
	}
	for(int i=0; i<=45; i++){
		c[i][0] = 1;
		for(int j=1; j<=i; j++)
			c[i][j] = c[i-1][j-1] + c[i-1][j];
	}
	for(int i=0; i<(1<<n); i++)
		siz[i] = siz[i>>1] + (i&1);
	for(int i=0; i<(1<<n); i++){
		for(int j=0; j<n; j++)
			if(i&(1<<j))
				cnt[i] += siz[w[j]&i];
		cnt[i] >>= 1;
	}
	for(int s=0; s<(1<<n); s++){
		if(siz[s]==1){
			g[s][0] = 1;
			continue;
		}
		int p=s&-s;
		for(int t=(s-1)&s; t; t=(t-1)&s)
			if(t&p)
				for(int i=0; i<=cnt[t]; i++)
					for(int j=0; j<=cnt[s^t]; j++)
						f[s][i+j] += g[t][i] * c[cnt[s^t]][j];
		for(int i=0; i<=cnt[s]; i++)
			g[s][i] = c[cnt[s]][i] - f[s][i];
	}
	double ans=0;
	for(int i=0; i<=m; i++)
		ans += f[(1<<n)-1][i] / c[cnt[(1<<n)-1]][i];
	ans /= m + 1;
	printf("%.6f
", ans);
	return 0;
}
原文地址:https://www.cnblogs.com/poorpool/p/9102295.html