牛客练习赛86 C取钱 贪心

题目链接

https://ac.nowcoder.com/acm/contest/11176/C

题意

取钞机有n种面值的纸币(无穷张),第一种始终为1.会优先给你大的,给出q个询问,最多取k块钱情况下,最多拿多少张钱。

思路

我们定义cost[i]为不使用i+1的纸币时取多少钱答案最大,gain[i]为此时对应的钱。
显然cost[1]=gain[1]=a[2]-1.
我们考虑递推。

当我们用两种钱时,我们得到的钱是两部分,由1支付的和由2支付的。为了不获得第三种纸币,我们最多拿a[3]以下的钱,为了获得1支付的最大值gain[1],我们在获得2支付的钱后,需要剩下cost[1]的钱,那么也就是可以贪心的拿出a[3]-1-cost[1]的钱获得2支付。我们把这部分钱除以a[2],得到的值t就是能获得t张a[2]。那么gain[2]=gain[1]+t,cost[2]=cost[1]+t*a[2]。就很容易写出递推式了。

之后对于每个询问k,我们二分查找出比他小的第一个cost的值和它对应的下标pos。对于k和cost[pos]的差值部分,我们用pos+1号纸币支付,就可以得到最终花费和最终得到的钱币数了。注意一些实现细节就可以了。

代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
#define int long long
//#define double long double
using namespace std;
	typedef long long ll;
	const int maxn=2000005;
	const int inf=0x3f3f3f3f3f3f3f3f;
	int n,m,k;
    int a[maxn];
    int cost[maxn],gain[maxn];
    int ans;
	signed main(){
        IOS
		#ifndef ONLINE_JUDGE
		    freopen("IO\\in.txt","r",stdin);
		    freopen("IO\\out.txt","w",stdout);
        #endif
		int tn=1;
        cin>>n;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        cost[1]=gain[1]=a[2]-1;
        for(int i=2;i<n;i++){
            int k=(a[i+1]-cost[i-1]-1)/a[i];
            cost[i]=k*a[i]+cost[i-1];//只用到i纸币时,也就是不会被i+1号'截胡'时,选多少钱最优
            gain[i]=k+gain[i-1];//这时答案是多少
        }
        cost[n]=inf;
        cin>>m; 
        while(m--){
            cin>>k;
            int pos=upper_bound(cost+1,cost+1+n,k)-cost;
            pos--;
            int a1,a2;
            a1=((k-cost[pos])/a[pos+1])*a[pos+1]+cost[pos];
            a2=((k-cost[pos])/a[pos+1])+gain[pos];//前半部分就是上文说的t
            cout<<a1<<' '<<a2<<endl;
        }
	} 
						
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值