嘘~ 正在从服务器偷取页面 . . .

CF913C Party Lemonade 题解


CF913C Party Lemonade 题解

题目链接:CF913C Party Lemonade

题意

新年派对少了柠檬水就不是真正的新年派对!

如往常一样,你期望有很多客人,购买柠檬水已成为一种愉快的必需品。

你最喜欢的商店以不同容量和不同价格销售柠檬水。

一瓶第 \(i\) 类型的柠檬水容量为 \(2^{i-1}\) 升,价格为 \(c_i\) 卢布。商店中每种类型的柠檬水瓶数可以被认为是无限的。

你想购买至少 \(L\) 升的柠檬水。你需要花费多少卢布呢?

输入格式

第一行包含两个整数 \(n\)\(L\left(1 \leq n \leq 30 ; 1 \leq L \leq 10^9\right)\) - 商店中瓶子类型的数量和所需的柠檬水数量(升)。 第二行包含 \(n\) 个整数 \(c_1, c_2, \ldots, c_n\left(1 \leq c_i \leq 10^9\right)\) - 不同类型柠檬水瓶子的价格。

输出格式

输出一个整数 - 为了购买至少 \(L\) 升柠檬水,你需要支付的最少卢布数。

注意到如果 \(2w_{i - 1} < w_i\) ,我们会用 \(2w_{i - 1}\) 替代,因此可以预处理出每个 \(i\) 的最小花费。

题目要求的是体积不小于 \(L\) 的柠檬汁最少要多少钱,这种二维的问题还是套路地去二分钱数。

由于我们已经预处理过 \(w_i\) 了,所以一定有 \(2w_{i-1} \ge w_i\) ,也就是说我们只需要从大到小贪心买。

在题解区学了一个新的二分写法,挺有意思的,原理稍微讲一下吧。

每次探索的范围是 \((p,~p+2^{k+1}]\) ,如果 \(p + 2^k\) 够,那就在 \((p,p + 2^k]\) 里找,否则在 \((p + 2^k, p + 2^{k + 2}]\)

找到最后会卡在 \((p,p+1]\) ,所以答案就是 \(p + 1\) 。大概意思懂了就好(因为我也不知道这个有啥用

时间复杂度 \(\mathcal{O}(n+\log^2M)\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)())

int n,L,w[31];
bool check(int x)
{
    int sum = 0;
    for(int i = 30; ~i; i--) if(x >= w[i]) { 
        sum += (1 << i); x -= w[i];
    }
    return sum >= L;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> L; cin >> w[0];
    for(int i = 1; i < n; i++) {
        cin >> w[i]; if(w[i] > w[i - 1] * 2) w[i] = w[i - 1] * 2;
    }
    for(int i = n; i <= 30; i++) w[i] = w[i - 1] * 2;
    int p = 0, k = 1; while(k) {
        // cout << "p = " << p << ',' << "k = " << k << '\n';
        if(!check(p + k)) p += k, k <<= 1; else k >>= 1;
    }
    cout << (p + 1) << '\n';
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录