http://acm.hdu.edu.cn/showproblem.php?pid=4336
题意:
给出n种不同卡片在买的小吃力里面出现的可能,求凑齐n种卡片要买的小吃的平均数量。
思路:
根据官方解题报告做的:
设卡片的分布p=(p1,p2,...,pn),T(p)表示拿到所有卡片时买的零食数目,有
由容斥原理得,
#include <cstdio> #include <iostream> using namespace std; const int maxn = 22; double p[maxn]; int main() { int n,i,j; while (~scanf("%d",&n)) { for (i = 0; i < n; ++i) scanf("%lf",&p[i]); double ans = 0.0; //根据二项式定理C(n,0)+C(n,1) + ... + C(n,n) = 2^n //所以这里2^n - 1种可能,枚举 for (i = 1; i < (1<<n); ++i) { int ct = 0; double tmp = 0.0; for (j = 0; j < n; ++j) { if (i&(1<<j))//检查0到n中存在于i状态的点 { ct++; tmp += p[j]; } } //鸽巢定理 if (ct&1) ans += 1.0/tmp; else ans -= 1.0/tmp; } printf("%.4lf\n",ans); } return 0; }
用一个状态表示当前抽到的卡片的状况,1代表尚未拿的卡片,有d[now]=x*d[now]+sigma(si*pi*(now^(1<<i)))+1,si表示stat中该位是0还是1,x表示停留在该状态的概率,即没拿到其它卡片的概率(没抽到卡片+抽到当前已有卡片),移项可以得到d[now]=sigma(..)/(1-x)。
#include <string.h> #include <stdio.h> int n; double p[25],d[1<<21]; //d[stat] stat中为1的位表示尚未拿的卡片 //d[now]=x*d[now]+sigma(si*pi*(now^(1<<i)))+1,si表示stat中该位是0还是1 //移项有d[now]=sigma(..)/(1-x) x表示停留在该状态的概率,即没拿到其它卡片 int main(){ while(scanf("%d",&n)!=EOF){ double tot=0; for(int i=0;i<n;i++){ scanf("%lf",&p[i]); tot+=p[i]; } tot=1-tot,d[0]=0; for(int i=1;i<(1<<n);i++){ double x=0,sigma=1; for(int j=0;j<n;j++){ if(((i>>j)&1)==0)x+=p[j]; else sigma+=p[j]*d[i^(1<<j)]; } d[i]=sigma/(1-tot-x); } printf("%.5f\n",d[(1<<n)-1]); } return 0; }