您的位置:首页 > 其它

codeforces 623D

2016-04-15 14:41 369 查看

原题

原题链接

题目大意

给定n≤100n\leq100个人,每轮随机选取一个人,每个人被选的概率为pi(精度为0.01),∑pi=1p_i(精度为0.01),\sum p_i=1,游戏结束当且仅当每个人被抓住一次或以上,问,在最优策略下,期望结束轮数是多少,要求答案精度为10−610^{-6}。

解题思路

设fi,jf_{i,j}表示第ii轮结束之后,第jj个人被抓过的概率。

设gig_i表示第ii轮结束之后,所有人都被抓过的概率。

显然gi=∏nj=1fi,jg_i=\prod_{j=1}^{n} f_{i,j}.

∵Ans=∑+∞i=1i∗(gi−gi−1)\because Ans=\sum_{i=1}^{+\infty} i*(g_i-g_{i-1})

∴\therefore最优策略就是,尽量使得ii较小时,gi−gi−1g_i-g_{i-1}较大。

先看看fi,jf_{i,j}和fi−1,jf_{i-1,j}的关系。

1)fi,j=fi−1,j1)f_{i,j}=f_{i-1,j},第ii轮不选jj.

2)fi,j=fi−1,j+(1−fi−1,j)∗pj2)f_{i,j}=f_{i-1,j}+(1-f_{i-1,j})*p_j,第ii轮选jj.

∴gi=gi−1∗fi,j/fi−1,j\therefore g_i=g_{i-1}*f_{i,j}/f_{i-1,j}

只要求fi,j/fi−1,jf_{i,j}/f_{i-1,j}最大即可,这个可以枚举,或者用数据结构维护。

其实3∗1053*10^5轮过后答案就不会再有大于10−610^{-6}的误差了。

误差分析

gt≥ (1−0.99t/100)100 ≥1−100⋅0.99t / 100.g_t\geq (1-0.99^{t/100})^{100} \geq1-100·0.99^{t / 100}.

∑+∞t=N+11−gt≤100∗∑+∞t=N+10.99t/100\sum_{t=N+1}^{+\infty} 1-g_t\leq100*\sum_{t=N+1}^{+\infty}0.99^{t/100}.

所以大概3∗1053*10^5次运算之后答案就精准了。

参考代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define maxn 105
#define lim 300000
#define ld long double
#define mem(a,b) memset(a,b,sizeof(a))
#define eps 1e-15
using namespace std;

ld f[2][maxn];

ld g[2],ans;

ld p[maxn];

int n;

int main(){
scanf("%d",&n);
fo(i,1,n) {
cin>>p[i];
p[i]/=100;
}
int last=0,now=1;
fo(i,1,lim) {
last^=1;
now^=1;
ld best=0;
int w=0;
fo(j,1,n) {
ld thi=(1-f[last][j])*p[j]/f[last][j];
if (thi>best) {
best=thi;
w=j;
}
}
fo(j,1,n) {
if (j==w) {
f[now][j]=f[last][j]+(1-f[last][j])*p[j];
}
else {
f[now][j]=f[last][j];
}
}
if (f[last][w]<eps) {
g[now]=1;
fo(j,1,n) g[now]=g[now]*f[now][j];
}
else g[now]=g[last]*f[now][w]/f[last][w];
ans=ans+(g[now]-g[last])*i;
}
double pri=ans;
printf("%.16lf",pri);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: