有n种卡,每一卡包有概率(p_i)出现卡i,只会出现一张以下的卡,询问卡包的期望数包含所有种类的卡,(1 <= N <= 20)。
解
法一:容斥原理
注意到数据范围很小,再此我们能很轻松地求出一种卡摸到的期望,而此时摸到的期望包含了其他的部分,于是考虑容斥。
不难有一种卡i,其摸到的期望数为(frac{1}{p_i}),而对于摸到卡i,或者j的期望数不难得知,即把它们看成一个整体(frac{1}{p_i+p_j}),于是我们可以以此为容斥依据,进行容斥即可。
参考代码:
#include <iostream>
#include <cstdio>
#define il inline
#define ri register
using namespace std;
double w[20];
int main(){
double sxr,ans;
int n,i,j,li,tot;
while(scanf("%d",&n)!=EOF){
for(i=0;i<n;++i)scanf("%lf",&w[i]);
li=1<<n,ans=0;
for(i=1;i<li;++i){
tot&=0,sxr=0;
for(j=0;j<n;++j)
if(i>>j&1)sxr+=w[j],++tot;
if(tot&1)ans+=1/sxr;
else ans-=1/sxr;
}printf("%.5lf
",ans);
}
return 0;
}
法二:无后效性处理
注意到为期望题,而样本空间无限大,考虑无后效性做法,即以期望代无限状态,设(E(x))表示已经摸到x对应二进制的卡种数的期望卡包数(如(E(3))表示已经摸到第1中卡和第二种卡的卡包数期望),于是不难有转移
[E(x)=1+sum E(x)p_i+sum E(y)p_j
]
其中(E(x)p_i)表示摸到已经摸过的卡,概率分别为(p_i),y则是对应二进制位已经把没摸过的卡记录下来,概率分别为(p_j)。
例如,只有2种卡,设(p_0)为没有摸到任何卡的概率
[E(0)=1+E(0)p_0+E(1)p_1+E(2)p_2
]
[E(1)=1+E(1)(p_0+p_1)+E(3)p_2
]
[E(2)=1+E(2)(p_0+p_2)+E(3)p_1
]
[E(3)=0
]
于是对一般式变换一下,我们有
[E(x)=frac{1+sum E(y)p_j}{(1-sum p_i)}
]
以此为递推依据记忆化搜索即可。
参考代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
using namespace std;
int n;double w[21];
double dp[1048576];
il double search(int);
int main(){
int i,li;
while(scanf("%d",&n)!=EOF){
w[n]=1;for(i=0;i<n;++i)scanf("%lf",&w[i]),w[n]-=w[i];
memset(dp,-127,sizeof(dp)),li=(1<<n)-1,dp[li]=0;
printf("%.5lf
",search(0));
}return 0;
}
il double search(int er){
if(dp[er]>=0)return dp[er];
int i;double mom(1-w[n]),son(1);
for(i=0;i<n;++i)
if(er>>i&1)mom-=w[i];
else son+=search(er|1<<i)*w[i];
return dp[er]=son/mom;
}