原题链接
第一篇题解挺好的
思路
根据期望的定义:
E
=
∑
f
(
i
)
∗
d
(
i
)
E=\sum f(i)*d(i)
E=∑f(i)∗d(i),其中,f(i)为i牌的出牌概率。
之后是如何求f(i):
读原题,有个点:当出了一张牌后,结束本轮游戏。
那么,假设说,在r轮中,在i之前的i-1张牌中,有j张牌被打出,那么,而也就是说,会有r-j轮是会考虑到第i张牌的,因此,我们可以得到
f
(
i
)
=
∑
d
p
[
i
−
1
]
[
j
]
∗
(
1
−
(
1
−
p
(
i
)
)
r
−
j
)
f(i)=\sum dp[i-1][j]*(1-(1-p(i))^{r-j})
f(i)=∑dp[i−1][j]∗(1−(1−p(i))r−j)其中:p(i)为i的发动概率,dp[i][j]为前i张牌中,经过r轮后,打出了j张的概率。
之后,是维护dp。dp[i][j]从两个地方转移来:i张中选j张,第j张可能是i,也可能不是,所以,有两个来源:
1、
d
p
[
i
]
[
j
]
+
=
d
p
[
i
−
1
]
[
j
]
dp[i][j]+=dp[i-1][j]
dp[i][j]+=dp[i−1][j],就是前i-1中已经选了j张,我们转移过来便可。表示第i张牌并没有选到。
2、
d
p
[
i
]
[
j
]
+
=
d
p
[
i
−
1
]
[
j
−
1
]
∗
[
1
−
(
1
−
p
(
i
)
)
r
−
j
+
1
]
dp[i][j]+=dp[i-1][j-1]*[1-(1-p(i))^{r-j+1}]
dp[i][j]+=dp[i−1][j−1]∗[1−(1−p(i))r−j+1],就是前i-1中已经选了j-1,选上第i张便可。由于前面选了j-1张,所以有r-j+1轮会考虑到i牌,所以
∗
[
1
−
(
1
−
p
(
i
)
)
r
−
j
+
1
]
*[1-(1-p(i))^{r-j+1}]
∗[1−(1−p(i))r−j+1]。注意,这里j需要注意不要越界。
边界条件是为dp[0][0]=1。
然后这些过程倒着推回去就行了。
AC代码
#pragma GCC optimize(2)
#include <iostream>
#include <map>
#include <ctime>
#include <vector>
#include <climits>
#include <algorithm>
#include <random>
#include <cstring>
#include <cstdio>
#include <map>
#include <set>
#include <bitset>
#include <queue>
#define inf 0x3f3f3f3f
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(register int i = a; i <= n; ++ i)
#define per(i, a, n) for(register int i = n; i >= a; -- i)
//#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
{
write(x/10);
}
putchar(x%10+'0');
}
template<typename T> void read(T &x)
{
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int lcm(int a,int b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){//¿´ÊÇ·ñÒªmod
ll ans=1;
while(n){
if(n&1) ans=(ans*a)%mod;
a=a*a%mod;
n>>=1;
}
return ans%mod;
}
//==============================================================
const int maxn=300;
struct Card{
double p;
int d;
Card(double pp,int dd){
p=pp;
d=dd;
}
};
vector<Card>da;
int t,n,r;
double pows[300][140];
inline void pre_deal(){
memset(pows,0,sizeof(pows));
rep(i,1,n){
pows[i][0]=1;
rep(j,1,r){
pows[i][j]=pows[i][j-1]*(1-da[i].p);
}
}
/*rep(i,1,n){
rep(j,1,r){
cerr<<pows[i][j]<<" ";
}
cerr<<endl;
}*/
}
double dp[300][140];
double f[300];
double solve(){
memset(dp,0,sizeof(dp));
memset(f,0,sizeof(f));
dp[0][0]=1;
rep(i,1,n){
rep(j,0,r){
dp[i][j]+=dp[i-1][j]*pows[i][r-j];
if(j) dp[i][j]+=dp[i-1][j-1]*(1-pows[i][r-j+1]);
}
}
double res=0;
rep(i,1,n){
rep(j,0,r){
f[i]+=dp[i-1][j]*(1-pows[i][r-j]);
}
}
rep(i,1,n){
res+=da[i].d*f[i];
}
return res;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
//clock_t c1 = clock();
//===========================================================
read(t);
while(t--){
da.clear();
da.push_back(Card(0,0));
read(n),read(r);
rep(i,1,n){
int d;
double p;
scanf("%lf %d",&p,&d);
da.push_back(Card(p,d));
}
pre_deal();
printf("%.10lf\n",solve());
}
//===========================================================
//std::cerr << "Time:" << clock() - c1 << "ms" << std::endl;
return 0;
}