有 n n n个物理实验室,第 i i i个实验室有 a i a_i ai个人,他们全都在打游戏。
同学 A A A可以选择进入一间实验室 i i i,然后让其中的所有 a i a_i ai个人停止打游戏。
然后老师 B B B可以选择进入一间实验室 j j j,然后抓住其所有在打游戏的人。
同学 A A A的目标是让老师 B B B抓到的人最少,而老师的目标是抓到最多的人。
老师 B B B在决策时无法知道同学 A A A进入过哪个实验室。
两人都选择最优策略,问老师期望可以抓到多少人,注意两个人的决策都是可以基于概率的。
也就是说,你要找到一个 m m m,使得无论老师怎么操作,总存在同学的一种方案使得被抓的人数期望 ≤ m \leq m ≤m;同时无论同学怎么操作,总存在老师的一种方案使得被抓的人数期望 ≥ m \geq m ≥m。
输出被抓的期望人数,相对误差在 1 0 − 9 10^{-9} 10−9即视为正确。
1 ≤ n ≤ 30 , 0 ≤ a i ≤ 40 1\leq n\leq 30,0\leq a_i\leq 40 1≤n≤30,0≤ai≤40
二分答案 m i d mid mid,我们只关注同学能否使得被抓人数 ≤ m i d \leq mid ≤mid。
那么, a i ≤ m i d a_i\leq mid ai≤mid的实验室就无关紧要了,我们只关注 a i > m i d a_i>mid ai>mid的实验室。设同学 A A A有 p i p_i pi的概率进入实验室 i i i,那么如果老师选择进这个实验室,则期望被抓的人数为 ( 1 − p i ) × a i (1-p_i)\times a_i (1−pi)×ai。
所以,对于任意的 a i a_i ai,都要满足 ( 1 − p i ) × a i ≤ m i d (1-p_i)\times a_i\leq mid (1−pi)×ai≤mid,那么我们可以求出每个 p i p_i pi的下界,并加起来看看是否超过 1 1 1。如果超过 1 1 1的话,因为 p i p_i pi的总和要为 1 1 1,那就存在 p i p_i pi不能满足 ( 1 − p i ) × a i ≤ m i d (1-p_i)\times a_i\leq mid (1−pi)×ai≤mid,那么 m i d mid mid就不可取;否则, m i d mid mid就是可取的。
假设二分得出的值为 a n s ans ans,那么我们来证明 a n s ans ans就是答案。
上面已经证明了同学能使期望被抓的人数 ≤ m \leq m ≤m,下面来证明老师能使期望被抓的人数 ≥ m \geq m ≥m。
假设有 k k k个大于 a n s ans ans的 a i a_i ai,则由 ( 1 − p i ) × a i = a n s (1-p_i)\times a_i=ans (1−pi)×ai=ans可得 p i = a i − a n s a i p_i=\dfrac{a_i-ans}{a_i} pi=aiai−ans,于是 ∑ p i = ∑ a i − a n s a i = m − a n s ∑ 1 a i \sum p_i=\sum \dfrac{a_i-ans}{a_i}=m-ans\sum\dfrac{1}{a_i} ∑pi=∑aiai−ans=m−ans∑ai1, a n s = m − 1 ∑ 1 a i ans=\dfrac{m-1}{\sum\frac{1}{a_i}} ans=∑ai1m−1。
给出老师的一种策略:以 1 a j ( ∑ 1 a i ) \dfrac{1}{a_j(\sum\frac{1}{a_i})} aj(∑ai1)1的概率选择进入第 j j j个实验室,那么其最坏能抓到的人数为
min t = 1 n ( ∑ j ≠ t 1 a j ( ∑ 1 a i ) × a j ) = m − 1 ∑ 1 a i = a n s \min\limits_{t=1}^n(\sum\limits_{j\neq t}\dfrac{1}{a_j(\sum\frac{1}{a_i})}\times a_j)=\dfrac{m-1}{\sum\frac{1}{a_i}}=ans t=1minn(j=t∑aj(∑ai1)1×aj)=∑ai1m−1=ans
其中 t t t枚举的是同学选择进入的房间。
那么,这样就可以证明 a n s ans ans就是答案。
时间复杂度为 O ( n log v ) O(n\log v) O(nlogv),其中 v v v为 a n s ans ans的值域。
#include
using namespace std;
const long double eps=1e-12;
int n,mx,a[35];
long long ans;
bool check(long double k){
long double re=0;
for(int i=1;i<=n;i++){
if(a[i]<=k) continue;
re+=1-k/a[i];
}
if(re>1) return 0;
return 1;
}
int main()
{
// freopen("game.in","r",stdin);
// freopen("game.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
mx=max(mx,a[i]);
}
long double l=0,r=mx,mid;
while(r-l>=eps){
mid=(l+r)*0.5;
if(check(mid)) r=mid;
else l=mid;
}
printf("%.12Lf",r);
return 0;
}