C.取钱
题目链接:<>
题意:
取款机中有 n 种面额不同的钞票(保证\(a[1]=1,a[i-1] < a[i] < a[i+1]\)),现有 x 元,只能取一次且只能取不超过 x 元,取款机取款原则为从大到小兑换,若当前剩余要取出的钱数大于面额 a[i],则只会取出面额为 a[i]的钞票,直到剩余要取出的钱数小于 a[i],问最多能兑换多少张钞票。q 次查询,每次查询给定一个 x,取款金额不超过 x,输出取款的金额以及获得的钞票数量,若有多个取款金额取出的纸币数都为最大值,输出其中任意一个即可。
思路:
贪心,预处理计算一个 num 数组和 sum 数组,num[i]表示前 i 种钞票最多可以有多少张,sum[i]表示保证前 i 种钞票总数量最大的情况下这些钞票的总价值最小多少
我们显然可以知道对于前 i 种钞票,若要使它们的数量最大,则它们的总价值不能超过第 i+1 种钞票的面额,于是我们可以每次贪心地计算前 i 种钞票的总数量以及对应的最小总金额,每次查询时在面额数组 a 中二分查找当前金额 x 大小,对于\(a[i] \le x < [i+1]\),使用不超过 x 元最多可以取出的钞票数即为前 i-1 种钞票的最大总数量再加上剩下的钱(即 x 减去前 i-1 张钞票的总金额)可以取出的面值为 a[i]的钞票的最大数量,再计算一下取出的这些钞票的总金额即可
代码:
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 2e5 + 5;
typedef long long ll;
ll n, q; //n种面额的钱,q次询问
ll a[maxn]; //每种钱的面额
ll num[maxn], sum[maxn]; //num[i]表示保证前i种钞票总数量最多多少,sum[i]表示保证前i种钞票总数量最多的前提下前i种钞票总价最少为多少
void init()
{
ll maxsum, nowsum, nownum;
//maxsum,当前面额以及当前面额以下的钞票总价最多多少
//nowsum,保证小于当前面额的钞票数量尽可能多时当前面额的钞票总价最多多少
//nownum,当前面额的钞票最多多少张
num[0] = sum[0] = 0;
for (int i = 1; i <= n - 1; i++)
{
maxsum = a[i + 1] - 1; //当前面额以及当前面额以下的钞票总价最多不超过下一种钞票的面额
nowsum = maxsum - sum[i - 1];
nownum = nowsum / a[i];
num[i] = num[i - 1] + nownum;
//(前i种钞票可能的最大数量)等于(前i-1种钞票可能的最大数量)加上(当前钞票(在前i-1种钞票数量尽可能多的前提下)的最大数量)
sum[i] = sum[i - 1] + a[i] * nownum;
//前i种钞票数量最大的前提下的最小总价
//cout << i << ":" << num[i] << " " << sum[i] << endl;//测试了一下数据
}
}
void solve(ll t)
{
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
init();
cin >> q;
ll x;
for (int i = 1; i <= q; i++)
{
cin >> x;
ll *pos = upper_bound(a + 1, a + 1 + n, x);
//不能用lower_bound,因为用lower_bound则a[pos-a]>=x,a[pos-a-1]<x,无法确定x是比a[pos-a-1]大一点点,但没大到a[pos-a]的大小,还是x=a[pos-a]
ll lpos = pos - a - 2;
ll res = x - sum[lpos];
//a[pos-a]>x,a[pos-a-1]<=x,x-sum[pos-a-2]即为保证前pos-a-2种钞票数量最多的前提下剩下的钱
ll rnum = max(0LL, res / (*(pos - 1)));
//rnum表示剩下的钱最多可以换多少张面额为num[pos-a-1]的钞票
//printf("pos:%d,a:%d\n,pos-a:%d,pos-1:%d\n", pos, a, pos - a, pos - 1);//用来测试了一下取地址原理
cout << sum[lpos] + rnum * (*(pos - 1)) << " " << num[lpos] + rnum << endl;
//输出总价和总数量
}
}

浙公网安备 33010602011771号