P1853 投资的最大效益

题目:

  • Snipaste_2020-05-20_14-52-01.png

大致题意:

  • 这是完全背包。

  • 而且是加了点东西的完全背包。

  • f[i]表示总资产i的最大利息值。

  • 按照完全背包的模板来n次就能找出正确答案。

  • 在完全背包的循环执行完毕后则需要用s加上f[s],因为f[s]只是总资产s的利息。

  • 那么代码便是:

    for(int i=1;i<=n;++i){
        for(int j=1;j<=d;++j){
            for(int k=w[j];k<=s;++k){
                f[k]=max(f[k],f[k-w[j]]+v[j]);
            }
        }
        s+=f[s];
    }
    
  • 但是评测记录告诉我们,TLE了。。

  • 虽然只有一个点TLE,但他就是TLE了!

  • 所以我们需要优化,怎么优化呢?我也不知道

  • 说明/提示里有段话说的是且a是1000的倍数,根据这句话我们就可以做出优化了。

  • 怎么根据这个优化呢?既然a是1000的倍数,那么在上述代码中的k变量在循环中就可以做出相应的整改了。

  • 因为a就是上述代码里面的w[j],所以k一开始就是w[j],也就是说k一开始是1000的倍数。

  • 那么在下面的公式中,如果k是1001也不会与1000有什么不同,也就是说只要k不是1000的倍数的时候,里面的公式做的都是无用功,浪费了很多时间。

  • 既然这样,那么我们就可以把++k改为k+=1000,这样就可以省下了不少的时间。

  • 但是这样还是有些bug,这bug并不是指时间问题,而是指s+=f[s]上,因为s有可能不是1000的倍数,那么就会加上一些奇奇怪怪的数,导致WA掉。

  • 所以就需要改一改,怎么改呢,既然s并没有被遍历到,但是s的利息s-s%1000的利息一样,所以把s+=f[s]中的f[s]改为f[s-s%1000]就好了。

  • 至此dp完毕。

Code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <list>
using namespace std;
#define R read()
#define GC getchar()
#define ll long long
#define ull unsigned long long
#define INF 0x7fffffff
#define LLINF 0x7fffffffffffffff
ll read(){
    ll s=0,f=1;
    char c=GC;
    while(c<'0'||c>'9'){if(c=='-')f=-f;c=GC;}
    while(c>='0'&&c<='9'){s=s*10+c-'0';c=GC;}
    return s*f;
}
int s,n,d;
int w[20],v[20];
int f[10000010];
int main(){
    s=R;n=R;d=R;
    for(int i=1;i<=d;++i){//输入
        w[i]=R;v[i]=R;
    }
    for(int i=1;i<=n;++i){//投资n年
        for(int j=1;j<=d;++j){//完全背包的模板
            for(int k=w[j];k<=s;k+=1000){
                f[k]=max(f[k],f[k-w[j]]+v[j]);//平平无奇的转换公式
            }
        }
        s+=f[s-s%1000];//加上利息
    }
    printf("%d",s);//输出
    return 0;
}
原文地址:https://www.cnblogs.com/FUXyao/p/12927061.html