zoukankan      html  css  js  c++  java
  • 牛客练习赛86 C. 取钱(贪心/二分查找/DP/好题)

    链接:https://ac.nowcoder.com/acm/contest/11176/C
    来源:牛客网

    题目描述

    某个国家的货币体系里有 nn 种面值不同的纸币,从小到大面值分别是 a1,a2,...,ana1,a2,...,an,a1=1a1=1。

    当取款人去 ATMATM 机取款 cc 元的时候, ATMATM 机按一种贪心的策略给取款人发放钞票,策略如下:

    首先,已发放钞票的集合是空集,每一次 ATMATM 机都会放一张当前可以放的最大面值的钞票进去,一直到集合里纸币面额等于 cc,然后将集合里的纸币吐给取款人。

    现在这个国家的公民觉得用钱把裤兜装的满满的会很有面子,但是他们又不想取出太多钱。现在他们问你:在最多取 bibi 元的情况下,最多可以获得多少张纸币。

    输入描述:

    第一行一个正整数 nn,表示钞票的面值数第二行 nn 个正整数 a1,a2,...,ana1,a2,...,an,表示 nn 种钞票的面值第三行一个正整数 qq,表示公民询问的数量接下来 qq 行每行一个整数 bibi1≤n≤2×1051≤n≤2×1051=a1<a2<...<an≤10181=a1<a2<...<an≤10181≤q≤2×1051≤q≤2×1051≤bi≤10181≤bi≤1018
    

    输出描述:

    对于每个查询输出两个数字:取款的金额以及获得的纸币数量若在不超过 bibi 的情况下有多个金额取款获得的纸币数量都是最大值,输出任意一个金额即可
    

    示例1

    输入

    复制

    4
    1 5 10 50
    3
    2
    8
    50
    

    输出

    复制

    2 2
    8 4
    49 9
    

    比赛的时候没想到二分的是凑出的钱数==也没想到怎么求凑出的钱数,看了别人的码总算会了

    关键思路就是贪心地用面额小的钱去凑。对于每个面值,先处理出总和小于下一个钞票面值的最多钞票数以及面值总和,然后对于每个输入w,二分查找最后一个面值总和x小于等于w的位置pos,算出w - x,这一部分就用a[pos + 1]来尽力凑,如果w - x < a[pos + 1]说明利用不上,那么直接设要取的钱是sum[pos]即可(题目说在最多取 bi元的情况下,当然也可以取不到)。

    #include <bits/stdc++.h>
    #define N 200005
    using namespace std;
    long long a[N], num[N], sum[N];//num[i]就是在凑出来的钱数小于a[i + 1]的情况下用面值小于等于a[i]的钞票能够得到的最多的张数 sum[i]为这些张数对应的钱数(小于a[i + 1])
    int n, q;
    
    int main() {
    	cin >> n;
    	for(int i = 1; i <= n; i++) {
    		cin >> a[i];
    	}
    	num[1] = sum[1] = a[2] - 1;//因为a1一定等于1
    	for(int i = 2; i <= n; i++) {
    		//贪心原则,优先用面值小的来凑,因此可以正着更新,有dp内味了
    		num[i] = num[i - 1] + (a[i + 1] - 1 - sum[i - 1]) / a[i];//要求钱数小于a[i + 1],所以这里是a[i + 1] - 1 - sum[i - 1]
    		sum[i] = sum[i - 1] + (a[i + 1] - 1 - sum[i - 1]) / a[i] * a[i];
    	}
    	cin >> q;
    	for(int i = 1; i <= q; i++) {
    		long long w;
    		cin >> w;
    		int pos = upper_bound(sum + 1, sum + n, w) - sum - 1;//找到最后一个小于等于w的位置,注意这里的上界,最多只能查找到n - 1的位置
    		cout << sum[pos] + (w - sum[pos]) / a[pos + 1] * a[pos + 1] << " " << num[pos] + (w - sum[pos]) / a[pos + 1] << endl;//注意剩下的钱必须要用a[pos + 1]来凑(题目要求)。注意这里的w不能-1,因为凑出来的钱数可以等于w
    	}
    	return 0; 
    }
    
  • 相关阅读:
    如何:将控件锁定到 Windows 窗体
    Linux 设置字符集
    sql 批量处理
    解决表被锁了
    oracle 分页模板
    创建用户及表空间
    恢复数据库数据
    instr vs like 效率
    自定义参数转换器
    spring boot 整合MyBatis
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/14993465.html
Copyright © 2011-2022 走看看