Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2421 Accepted Submission(s): 1140
Special Judge
题意:每包里面最多只有一张卡片(可能没有),要集齐n张不同的卡片(1<=n<=20)
问集齐n张卡片要买的包数期望。
算法:
1、 期望公式 :E=sum(xi*pi)。等于某一件事件的 状态 *它发生的概率。
在高中课本里就是列个分布列然后求期望。
我们用二进制枚举卡片表示各个状态。1表示已经集齐,0表示还没有。
从末态倒推到起始状态。
这里我们看每个状态是可能由哪个状态转移而来,乘以这个转移事件发生的概率
就是当前状态得到的期望了。
要注意的是这个转移事件发生的概率的理解:
它不是输入的那个概率,而是当前可以发生的转移中正在计算的转移所占的概率。
即如果当前状态能够从n种状态转移得来,则第i种发生的概率为pi/sum(p1....pn) ,其中sum(p1...pn)
p1...pn只是m个事件的子集(可以等于)
这就是为什么要除以能发生转移的概率和的原因。也是我高中学期望的时候老是出错的地方。
2、 容斥原理 :
容斥原理中奇加偶减
,比如:
如果被计数的事物有A、B两类,那么,A类B类元素个数总和= 属于A类元素个数+ 属于B类元素
个数—既是A类又是B类的元素个数。(A∪B = A+B - A∩B)
如果被计数的事物有A、B、C三类,那么,A类和B类和C类元素个数总和= A类元素个数+ B类
元素个数+C类元 素个数—既是A类又是B类的元素个数—既是A类又是C类的元素个数—既是B类
又是C类的元素个数+既是A类又是B类而且是C类的元素个数。(A∪B∪C = A+B+C - A∩B - B∩C - C∩A + A∩B∩C)
然后我们知道如果一件事发生的概率为pi,那么第一次发生这件事次数期望为1/pi。
同理,a和b这两件事发生的概率为p1,p2,则第一次发生某一件事发生的次数期望为1/p1+p2
如果一个事件发生的概率为p, 那么它第一次发生时的次数期望就是1/p
1: 1/p
2: (1-p)*p
3: (1-p)^2*p
......
n: (1-p)^(n-1)*p
以上求和,用错位相消的方法求出 E = 1/p
类似的,我们可以得出 如果两个事件发生的概率分别为p1,p2, 那么
第一次发生其中的某一件的次数期望就是1/(p1+p2)。
根据这个结论我们就可以用容斥原理来做这题了。
#include<stdio.h> double f[20]; int main() { int n,j,cnt,i; double sum,ans; while(~scanf("%d",&n)) { ans=0; for(i=1;i<=n;i++) scanf("%lf",&f[i]); for(i=1;i<1<<n;i++) { cnt=0; sum=0; for(j=1;j<=n;j++) { if(i&1<<(j-1)) { sum+=f[j]; cnt++; } } if(cnt%2==1) ans+=1.0/sum; else ans-=1.0/sum; } printf("%lf\n",ans); } return 0; }
状态压缩:
#include<cstdio> #include<cstring> double dp[1<<20],p[22]; int main() { int n,tot; double tmp; while(scanf("%d",&n)!=EOF) { for(int i=0;i<n;i++) scanf("%lf",&p[i]); tot=(1<<n)-1; dp[tot]=0.0; for(int s=tot-1;s>=0;s--) { dp[s]=1; tmp=0.0; for(int j=0;j<n;j++) { if(s&(1<<j)) continue; dp[s]+=dp[s|(1<<j)]*p[j]; tmp+=p[j]; } dp[s]/=tmp; } printf("%lf\n",dp[0]); } return 0; }