您的位置:首页 > 其它

bzoj 3925: [Zjoi2015]地震后的幻想乡

2015-04-07 11:22 393 查看
题目大意:给你n个点m条边,每条边的边权都是0~1的一个随机数,让你求一个最小瓶颈生成树的期望

虽然没有看懂,但还是先膜拜 http://wjmzbmr.com/archives/zjoi-2015-day-1%E9%A2%98%E8%A7%A3/
后来又膜拜了一下std,就幻想乡了。。。

就在这时,机房的zyf大神表示这题太水了,已经Ac了,于是速去膜拜

终于大概弄懂了

首先设f(x)为x==ans的概率密度函数,定义 F(x)=∫f(x)dx

我们惊讶的发现

ans=∫x*f(x)dx=∫xd(F(x))

再根据分部积分

ans=∫xd(F(x))=xF(x)-∫F(x)dx

然后我们发现F(x)代表答案<=ans的概率,即等价于每条边有x的概率出现,原图连通的概率,这个乱搞就可以了

#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
#define PB push_back
#define in(x,y) (((y)>>((x)-1))&1)
using namespace std;
const int maxn=1<<10,maxm=49;
typedef long long int64;
typedef __float128 ld;
typedef vector<int64> poly;
poly operator -(const poly &a,const poly &b){
poly res(max(a.size(),b.size()),0);
for (int i=0;i<a.size();++i) res[i]+=a[i];
for (int i=0;i<b.size();++i) res[i]-=b[i];
return res;
}
poly operator *(const poly &a,const poly &b){
poly res(a.size()+b.size()-1,0);
for (int i=0;i<a.size();++i) for (int j=0;j<b.size();++j) res[i+j]+=a[i]*b[j];
return res;
}
struct Te{int x,y;}e[maxm];
int n,m;
void init(){
scanf("%d%d",&n,&m);
for (int i=1;i<=m;++i) scanf("%d%d",&e[i].x,&e[i].y);
}
ld integrate(poly x){
ld ans=0;
for (int i=0;i<x.size();++i) ans+=ld(1.0)*x[i]/(i+1);
return ans;
}
poly f[maxn];
void work(){ // 状态为i的全部连通的概率(是一个关于每条边出现概率是x的多项式)
poly p,tmp; p.clear(); p.PB(1); p.PB(-1); int ss=1<<n;

f[1].clear(); f[1].PB(1);
for (int i=3;i<ss;i+=2){
f[i].clear(); f[i].PB(1);
for (int s=(i-1)&i;s;s=(s-1)&i) if (s&1){
int k=0;
for (int j=1;j<=m;++j) if (in(e[j].x,i) && in(e[j].y,i) && (in(e[j].x,s) ^ in(e[j].y,s))) ++k;
tmp=f[s]; while (k--) tmp=tmp*p; f[i]=f[i]-tmp;
}
}

poly ans; ans.clear(); ans.PB(1); ans=ans-f[ss-1];
printf("%.6f\n",(double)integrate(ans));
}
int main(){
init();
work();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: