洛谷P2721 小Q的赚钱计划
P2721 小Q的赚钱计划
题意:
你有一年时间,把 10w 元存银行变成更多钱,在特定时间区间内,你会有一些利息,不过不可中途退出。
分析
使用 dp 策略。
数组 \(f\) 用于存储一年中每一天的最大收益,初始值设为 \(100000\)。
输入数据包含 \(n\) 个投资,每个投资由以下信息表示:
- \(x\):投资的月份(两位数的整数)。
- \(y\):投资的日期(两位数的整数)。
- \(d\):投资持续的天数。
- \(c\):投资的回报率(以百分比表示)。
dp 过程如下:
对于每次投资,根据投资的回报率 \(c\)、持续天数 \(d\) 和一年 \(365\) 天的假设,计算每天的收益率 \(a_i\)。计算公式为:
\[a_i = c \times 0.01 \times (d \div 365.0) + 1
\]
计算每次投资的起始日(\(st_i\))和结束日(\(ed_i\)),使用 \(month\) 数组和给定的投资月份 \(x\) 和日期 \(y\) 进行计算。
循环遍历一年中的每一天,并更新当天的最大收益:
-
在第 \(i\) 天的最大收益初始化为前一天的最大收益(\(f_i = f_{i-1}\))。
-
然后,对于每次投资 \(j\):
如果投资 \(j\) 不是在第 \(i\) 天结束的(即 \(ed_j \ne i\)),意味着该投资对当天的收益没有贡献,所以跳过当前投资,继续下一个投资。如果投资 \(j\) 是在第 \(i\) 天结束的,dp 公式为:
\[f_i = \max(f_i, f[st_j - 1] \times a_j) \]比较第 \(i\) 天的最大收益与投资 \(j\) 开始前一天的最大收益乘以当天的收益率 \(a_j\),从而确保更新为当天的最优值。
接下来贴上代码……
AC Code
#include <bits/stdc++.h>//保命万能头
using namespace std;//标准命名空间
const int month[]={0,0,31,59,90,120,151,181,212,243,273,304,334,365};
//打表,表示每个月份的天数累加。例如,month[1]表示1月份的天数,month[2]表示1月份和2月份的天数之和。
double f[400]={100000},a[10010];
//f存储每天的最大收益,a存储每次投资的收益率
int n,st[10010],ed[10010],x,y,d;
//声明用于存储输入数据和计算过程中的临时变量
double c;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)//循环,用于读取每次投资的信息并计算收益率
{
scanf("%2d%2d%d%lf",&x,&y,&d,&c);
//使用scanf函数读取信息,因为scanf对精度有着特殊的处理
a[i]=c*0.01*(d/365.0)+1;
//根据读取的收益率c和持续天数d计算出收益率,并将其存储在数组a中
st[i]=month[x]+y;
//根据读取的月份x和日期y,计算出投资的起始日期在一年中的天数
ed[i]=st[i]+d-1;
//根据的起始日期和持续天数,计算出投资的结束日期
}
for(int i=1;i<=365;i++)//用于动态规划计算
{
f[i]=f[i-1];
//动态规划的计算
for(int j=1;j<=n;++j)
{
if(ed[j]!=i) continue;
//如果不在当天结束,跳过
f[i]=max(f[i],f[st[j]-1]*a[j]);
//更新当天的最大收益
}
}
cout<<fixed<<setprecision(2)<<f[365];
//保留两位小数输出
return 0;
//华丽结束
}