题目链接
计蒜客信息学1月CSP-J2模拟赛B题,https://nanti.jisuanke.com/t/43039。
本题难度不大,但是题目出得非常的巧。
题目
DD 现在养成了在银行存款的好习惯,DD 存款的方式是每年放入 N 元并将之前的所有本金和利息也一起投进银行。在每一年年终,DD 的存款都会增长 P%(下取整到最近整数)。在 Y 年之后,她想拥有最少 T 元,DD 现在想知道,每年投入的 N 元最少是多少能够在 Y 年后获得最少 T 元。
输入格式
第一行三个整数,分别表示 P, Y, T。
输出格式
共一行,输出 N 最少是多少。
样例输入
100 2 300
样例输出
50
数据范围
对于 30% 的数据,。
对于 60% 的数据,。
对于 100% 的数据,。
题目分析
题目要求
题目的意思就是根据存款利率(P)、存款年份(Y)和最终金额(T),倒推出存款金额(N)。
本题注意几个细节:
1、每年的金额需要下取整到最近整数。
2、每年将本金和利息也一起投进银行。
数学推导
因此,我们可以推算出:
1、第一年:。
2、第二年:。
3、第三年:。
4、...
Y、第Y年:
也就是说
问题归结到求出这个值即可。说干就干,也许我们就可以写出这样的一个代码。
题目坑点
1、计算利息的时候要使用浮点数,而题目提供的P是整数。
2、每年计算需要下取整。
直接计算代码(只能通过2组数据)
#include <bits/stdc++.h>
using namespace std;
int main(){
double p;
int y, t;
cin >> p >> y >> t;
p = 1+p/100.0;
double ans = 0;
for (int i=0; i<y; i++) {
ans += p;
p *= p;
}
ans = t/ans;
cout << (int)ceil(ans) << endl;
return 0;
}
别急,我们分析一下数据规模,注意,我们来看一下这个数据
,当
的时候将多大。
。
我去,这是一个天文数据,远远超过了C++最大的是数据类型unsigned long long的大小,也就是说只要数据量变大,这个程序就爆了。可以尝试提交一下,果然只能通过两组测试数据。
二分查找
由于数据量实在太大,没办法直接计算。我们可以知道,N的值范围必然是,程序的思路变成假设一个N值,验算在这样条件下,经过Y年后,将得到的数据。
为了降低复杂度,我们可以使用过二分查找,这样本题就变成一个标准的二分查找模板题。
#include <bits/stdc++.h>
using namespace std;
int main(){
double p;
long long y, t;
cin >> p >> y >> t;
p = 1+p/100.0;
//二分查找
int left=1;
int right=t;
int mid;
long long n;
while (left<=right) {
mid = (right+left)/2;
//根据的钱,计算y年后
n = 0;
for (int i=0; i<y; i++) {
n = (n+mid)*p;
if (n>t) {
break;
}
}
if (n>t) {
right = mid-1;
} else if (n<t) {
left = mid+1;
} else {
break;
}
}
cout << mid << endl;
return 0;
}
程序说明
1、对于坑点1,也就是利率计算问题。我们可以将P定义为double类型。
2、变量n的数据类型,不能使用int。在数据量大的时候,计算n很容易超过int数据范围,因此需要使用long long。
3、对于坑点2,也就是下取整问题。我们可以使用隐式数据转换来实现,也就是代码的
n = (n+mid)*p;
这个地方。当然也可以使用显示强制数据转换来实现。
4、在验证二分数据的时候,Line 21 ~ Lline 23,就是当计算出的时候,就不需要继续验证下去了。
5、由于个人水平问题,这个代码目前只能通过9组测试数据,还有一组测试数据错误,我会进一步验证一下问题在哪里。