题解:洛谷 P15256 [USACO26JAN2] Purchasing Milk B

【题目来源】

洛谷:[P15256 USACO26JAN2] Purchasing Milk B - 洛谷

【题目描述】

在国家牛奶日,农夫约翰正在提供桶装牛奶的独家优惠!他有 \(N\)\(1 \leq N \leq 10^5\))个交易,编号从 \(1\)\(N\)。对于第 \(i\) 个交易,他以 \(a_i\)\(1 \leq a_i \leq 10^9\)\(a_i < a_{i+1}\))牛币的价格提供 \(2^{i-1}\) 桶牛奶。同一个交易可以被购买任意非负整数次。

你正在考虑 \(Q\)\(1 \leq Q \leq 10^4\))个独立的询问。对于每个询问,你心中有一个整数 \(x\)\(1 \leq x \leq 10^9\)),你想知道购买至少 \(x\) 桶牛奶的最小成本。

【输入】

第一行包含两个整数 \(N\)\(Q\)

接下来的一行包含 \(a_1, a_2, \ldots, a_N\)

接下来的 \(Q\) 行,每行包含一个整数 \(x\),表示一个询问。

【输出】

对于每个询问,在新的一行输出最小成本。

注意:本题中可能涉及大整数,需要使用 64 位整数数据类型(例如,C/C++ 中的 long long)。

【输入样例】

2 4
10 15
1
2
6
7

【输出样例】

10
15
45
55

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 100005;
int n, q, ans, sum, minn = 1e18, x;  // n: 物品数, q: 查询数, x: 查询目标
int a[N];  // 物品价格

signed main()
{
    cin >> n >> q;  // 输入物品数和查询数
    for (int i = 1; i <= n; i++)  // 输入物品价格
    {
        cin >> a[i];
    }
    for (int i = 2; i <= n; i++)  // 预处理价格
    {
        a[i] = min(a[i], 2 * a[i - 1]);  // 确保价格合理
        if (i >= 32)  // 只考虑i≥32的情况
        {
            minn = min(minn, a[i]);  // 记录最小价格
        }
    }
    while (q--)  // 处理查询
    {
        cin >> x;  // 输入目标数量
        ans = minn;  // 初始答案
        sum = 0;  // 当前花费
        for (int i = min(31LL, n); i >= 1; i--)  // 从大到小处理
        {
            int base = pow(2, i - 1);  // 2^(i-1)
            sum += a[i] * (x / base);  // 用第i个物品填充
            int t = sum;
            if (x % base)  // 如果还有剩余
            {
                t += a[i];  // 多买一个
            }
            ans = min(ans, t);  // 更新最小花费
            x %= base;  // 更新剩余需求
        }
        cout << ans << endl;  // 输出答案
    }
    return 0;
}

【运行结果】

2 4
10 15
1
10
2
15
6
45
7
55
posted @ 2026-04-03 09:55  团爸讲算法  阅读(1)  评论(0)    收藏  举报