[刷题笔记] Luogu P1853 投资的最大效益

发布时间 2023-08-02 21:10:59作者: SXqwq

Problem

Solution

刚开始看这道题的时候不自主的想到了纪念品,但其实本题和纪念品还是有区别的。

  • 纪念品规定了每次只能买一个纪念品,而本题可以买无限个
  • 纪念品需要在原本的基础上买进卖出,钱有进有出,而本题时只有进,稳赚不赔。

本题和纪念品不同的第一点决定了它时完全背包,纪念品是01背包变形。第二点则决定了本题只需要记录最大利息即可,ans初始设置为初始的钱数,每年结束加上最大利息即可。

此外就是个完全背包板子。具体转化如下:

  • 把需投资的钱比作重量
  • 把利息比作价值

重量每年结束需要更替,替换成原来的金额+上一年的利息。

显然前一年如何不影响后一年的最优解,满足无后效性。以及每一年都可以视作独立的,显然最优方案是将前一年的股票全都出售利滚利投资下一年。符合dp

本题重点需要考虑如何设计状态以及读懂题意,明确与纪念品一题的区别。看出是完全背包,明确每一年互不干扰,由于稳赚不赔的特性最优解显然是每一年投资的全部取出来投资下一年,利滚利。

处理的时候包括动态的ans这里借鉴了纪念品一题。

本题还可以在处理下标的时候优化,避免下标过大。由于投资额都是1000的整数,故在处理的过程中都/1000不影响答案。

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 101000
#define INF 0x3f3f3f3f
using namespace std;
int s,n,d;
int ans = 0;
int w[N],v[N];
int f[N];
int main()
{
	scanf("%d%d%d",&s,&n,&d);
	ans = s;
	for(int i=1;i<=d;i++) scanf("%d%d",&w[i],&v[i]);
	for(int k=1;k<=n;k++)
	{
		memset(f,0,sizeof(f));
		for(int i=1;i<=d;i++) 
		{
			for(int j = w[i]/1000;j <= ans/1000;j++) 
			{
				f[j] = max(f[j],f[j-w[i]/1000]+v[i]);
			}
		}
		ans += f[ans/1000];
		}
		
	cout<<ans<<endl;
	return 0;
}