银行贷款
题目描述
当一个人从银行贷款后,在一段时间内他(她)将不得不每月偿还固定的分期付款。这个问题要求计算出贷款者向银行支付的利率。假设利率按月累计。
输入输出格式
输入格式
三个用空格隔开的正整数。
第一个整数表示贷款的原值,第二个整数表示每月支付的分期付款金额,第三个整数表示分期付款还清贷款所需的总月数。
输出格式
一个实数,表示该贷款的月利率(用百分数表示),四舍五入精确到(0.1\%)。
输入输出样例
输入样例 #1
1000 100 12
输出样例 #1
2.9
分析
二分答案做法
此题我想到了两种思路,先从第一个开始说吧,既然是从二分题单来的,就先说说二分答案做法。
二分答案做法其实就是二分利率,都是套板子的事,问题是check函数怎么写。
首先我们来看一下利率公式:
其中原题中的三个值:
第一个整数表示贷款的原值,第二个整数表示每月支付的分期付款金额,第三个整数表示分期付款还清贷款所需的总月数。
就分别对应(n, m, k)。
现在我们把这个式子变一下形。
等式左边其实就是公比为(dfrac{1}{1 + p})的等比数列求和。利用等比求和公式(S_n = a_1dfrac{1 - q ^ n}{1 - q})
可得:
此时原式可以转化为:
两边同( imes p):
两边再同时(- 1),然后( imes (-1)):
这样我们就能写出check函数了:
bool check(double x) {
return pow(1.0 / (1.0 + x), k) >= 1 - n / m * x;
}
小提示:pow函数需要
#include <cmath>
使用,pow(n, k)
是n的k次方的意思。至于check函数为啥用大于等于而不是等于,是为了二分缩小范围服务的。不懂没关系看代码你就懂了。
check函数写完后就简单了,二分整体代码见一会的总体代码部分。
哦对了关于这个二分的边界问题我要说明一下,此题中存在(p > 1)的情况,所以右边界不能定为1。
相信有的同学想问了,蟹蟹这里也没有说利率的范围啊,右边界不好定怎么办?
就是因为这个,我思考了另一种方法:
倍增做法
用倍增写这道题也是不错的选择。check函数还是那个check函数,整体都差不多,只是main函数中的二分答案变成了倍增而已,没什么好说的。
但是这种方案不用定右边界,完美解决了这个问题。
就这样吧,上代码。
代码
二分答案做法
/*
* @Author: crab-in-the-northeast
* @Date: 2020-06-16 09:18:57
* @Last Modified by: crab-in-the-northeast
* @Last Modified time: 2020-06-16 15:28:56
*/
//二分答案
#include <iostream>
#include <cstdio>
#include <iomanip>
#include <cmath>
const double eps = 1e-10;
double n, m, k;
bool check(double x) {
return pow(1.0 / (1.0 + x), k) >= 1 - n / m * x;
}
int main() {
std :: cin >> n >> m >> k;
double l = 0, r = 10086;
while (r - l >= eps) {
double mid = (l + r) / 2;//不能用位运算了啊啊啊啊啊啊啊啊暴风哭泣
if (check(mid)) r = mid;
else l = mid;
}
std :: cout << std :: fixed << std :: setprecision(1) << l * 100 << std :: endl;
return 0;
}
倍增做法
/*
* @Author: crab-in-the-northeast
* @Date: 2020-06-16 09:18:57
* @Last Modified by: crab-in-the-northeast
* @Last Modified time: 2020-06-16 15:27:24
*/
//倍增
#include <iostream>
#include <cstdio>
#include <iomanip>
#include <cmath>
const double eps = 1e-10;
double n, m, k;
bool check(double x) {
return pow(1.0 / (1.0 + x), k) >= 1 - n / m * x;
}
int main() {
std :: cin >> n >> m >> k;
double ans = 0;
double add = 0.1;
while (add >= eps) {
if (!check(ans + add)) {//注意这里是!check哦,原因自己想想
ans += add;
add *= 2.0;
}
else
add /= 2.0;
}
std :: cout << std :: fixed << std :: setprecision(1) << ans * 100 << std :: endl;
return 0;
}