2417. Loan Repayment

2417. Loan Repayment

题目描述

Farmer John 欠了 Bessie N 加仑牛奶(1≤N≤10^12)。他必须在 K 天内将牛奶给 Bessie。但是,他不想将牛奶太早拿出手。另一方面,他不得不在还债上有所进展,所以他必须每天给 Bessie 至少 M 加仑牛奶(1≤M≤10^12)。
以下是 Farmer John 决定偿还 Bessie 的方式。首先他选择一个正整数 X。然后他每天都重复以下过程:
(1)假设 Farmer John 已经给了 Bessie G 加仑,计算 (N−G)/X 向下取整。令这个数为 Y。
(2)如果 Y 小于 M,令 Y 等于 M。
(3)给 Bessie Y 加仑牛奶。
求 X 的最大值,使得 Farmer John 按照上述过程能够在 K 天后给 Bessie 至少 N 加仑牛奶 (1≤K≤10^12)。

输入

输入仅有一行,包含三个空格分隔的正整数 N、K 和 M,满足 K⋅M<N。
注意这个问题涉及到的整数规模需要使用 64 位整数类型(例如,C/C++ 中的“long long”)。

输出

输出最大的正整数 X,使得按照上述过程 Farmer John 会给 Bessie 至少 N 加仑牛奶。

样例输入

10 3 3

样例输出

2

数据范围限制

测试点 1-3 满足 K≤10^5。
测试点 4-10 没有额外限制。

提示

在这个测试用例中,当 X=2 时 Farmer John 第一天给 Bessie 5 加仑,后两天每天给 Bessie M=3 加仑。

一看到题目,我们便能知道这是一道二分题……
题目思路:

每次先用二分查找求出x,接着判断一下x是否满足要求。如果可以,那么尝试找更大的x,反之缩小x,最终我们会找到x的最大值。大家好像都知道
如何去判断x是否满足条件呢?
其实就是去模拟,但是暴力就只能对4个点,时间复杂度为O(k log n),所以这题的难点是如何进行优化。

设r为当前未还的奶量,day为当前的剩余偿还天数,q为每日的偿还量。
主要可以进行两方面的优化:
1.if q<=m,其实就不需要再模拟了,我们可以得到接下来的偿还量就是m*day。
2.if q>m,可能会有连续几天还同样的牛奶量的情况(49/10,45/10,41/10),如果知道这个连续的天数,不就可以按照上述方法进行优化吗?(假设这个天数为p)由题意得到两个不等式。通过化简可得p的值,如下图:
在这里插入图片描述

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
using namespace std;
const int MAX=2147483647;
const int N=1e6;
long long n,k,m,l,r,mid;
bool judge(long long x)
{
	long long r=n,day=k; //初始剩余未还牛奶数量和偿还期限; 
    while(1)
	{
        long long p,q;
        q=r/x;
        if(q<=m) return m*day>=r;  //小于m,剩余天数每天还m; 
        p=min(day,r/q-x+1);          //注意天数要在范围之内
        r-=p*q;
        day-=p;
        if(r<=0) return 1;  //期限内还完 
        if(!day) return 0;  //到期还未还完 
    } 
}
int main()
{
	//fre(loan);
	scanf("%lld%lld%lld",&n,&m,&k);
	l=1,r=n;
	while(l<r)
	{
		mid=(l+r+1)/2;
		if(judge(mid)) l=mid;
		else           r=mid-1;
	}
	printf("%lld\n",l);
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值