ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

牛客多校第五场补题

2021-08-02 16:03:43  阅读:199  来源: 互联网

标签:要开 需要 盒子 第五场 牛客 1e5 补题 2n 我们


B.Boxes
题意: N N N个装有黑白球的盒子(每个盒子一定有且只有一个球),你需要知道所有盒子里面都是什么球,为此你需要开盒子,打开第 i i i个盒子需要花费 w i w_i wi​的代价,同时你可以花费 C C C的代价先知道里面有多少个黑球,现在问你最小的期望花费。

题解:
很明显,我们可以有两种策略:

  • ①不询问,把所有盒子都开完。
  • ②先询问,然后再开盒子,直到开到不用开了为止。

      第一种策略很容易算,因为开每个盒子的概率是1,所以期望花费就是 Σ i = 1 n w i Σ^n_{i = 1}w_i Σi=1n​wi​。

      但是第二种策略我们就需要去考虑一个东西,对于当前盒子 i i i来说,什么情况下我们可以不用再开这个盒子 i i i了。
      其实就只有两种情况,要么剩下的盒子里(包括盒子 i i i)都是黑球了,或者都是白球了(也就是后缀是都是0或者后缀都是1的情况)。

例如:
如果盒子数是4的话,我们是这样去分析的:
      首先我会先去考虑是否需要开第一个盒子,不需要再开第一个盒子的情况就只有两种(0000,1111),也就是 2 / 2 4 2/2^4 2/24,那么我们必须要开第一个盒子的概率就是 1 − ( 2 / 2 4 ) 1-(2/2^4) 1−(2/24)。
      然后我考虑是否需要开第二个盒子,不需要再开第二个盒子的情况有(0111,1000,0000,1111),也就是 4 / 2 4 4/2^4 4/24,那么必须要开第二个盒子的概率就是 1 − ( 4 / 2 4 ) 1-(4/2^4) 1−(4/24)。
      同理,我们可以考虑是否开第三个盒子,求出必须要开第三个盒子的概率。

      这里需要注意,最后一个盒子是不需要去开的,因为我们询问过总数,所以我们开完前 n − 1 n -1 n−1个盒子之后,一定可以确定第 n n n个盒子里是 0 0 0还是 1 1 1。
      也就是说我们只需要确定 1 到 n − 1 1到n-1 1到n−1每个盒子必须要开的概率就可以。

      这里我们设必须要开第 i i i个盒子的概率为 p i p_i pi​,那么我们就可以得出 p i = 1 − 1 / ( 2 n − i ) pi = 1 - 1/(2^{n-i}) pi=1−1/(2n−i),所以我们第二种策略的期望花费就是: C + Σ i = 1 n − 1 w i ∗ ( 1 − 1 / ( 2 n − i ) ) C + Σ^{n-1}_{i = 1}w_i * (1 - 1/(2^{n-i})) C+Σi=1n−1​wi​∗(1−1/(2n−i))。接着我们就可以想到,因为 p i p_i pi​恒定,所以我们需要让 w i w_i wi​尽可能的小。

      如果我只开一个箱子,那么我一定是开最小价值的箱子,同理,开两个箱子一定是价值最小和价值次小的箱子。所以我们的开箱顺序就应该是从价值最小的箱子开到价值最大的箱子。需要对箱子的价值从小到大排序。

      答案就是对两种策略得到的期望花费求一个最小值就行。

一些细节:
      因为 n n n是 1 e 5 1e5 1e5,而我们需要求 1 − ( 1 / 2 1 e 5 ) 1 - (1/2^{1e5}) 1−(1/21e5), 一般来说可以用快速幂取模求,但是这道题目没有要求取模,我们没办法存下 2 1 e 5 2^{1e5} 21e5这么大的数。但是我们发现我们并不需要求出 2 n 2^n 2n,只需要直到 1 / 2 n 1/2^n 1/2n是多少就可以,可以发现这是一个分子为 1 1 1,且分母很大的分数,题目里给出的精度是 1 e 1e 1e- 6 6 6,这就意味着只要分母大到一定的程度,无论 1 / 2 n 1/2^n 1/2n是多少都没办法影响到我们的答案,我们可以把这个数看成 0 0 0。
      我写的时候是只要分母大于了 1 e 10 1e10 1e10,也就是这个数是小数点后 10 10 10位的时候,就不会再影响到答案。

AC代码:

#include<bits/stdc++.h>
using namespace std;

const int N = 1e5 + 100;
double w[N];

int main() {
    int n;
    double C;
    double ans1 = 0, ans2 = 0;
    scanf("%d%lf", &n, &C);
    for(int i = 1; i <= n; ++ i) {
        scanf("%lf", &w[i]);
        ans1 += w[i];
    }
    ans2 += C;
    long long res = 2;
    sort(w + 1, w + 1 + n);
    for(int i = 1; i <= n - 1; ++ i) {
        double p;
        if(res >= 1e10) p = 0;
        else p = 1.0/res;
        ans2 += w[n - i] * (1.0 - p);
        if(p != 0) res *= 2;
    }
    printf("%.6f\n", min(ans1, ans2));
}

标签:要开,需要,盒子,第五场,牛客,1e5,补题,2n,我们
来源: https://blog.csdn.net/weixin_45925735/article/details/119325412

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有