纪念品

基础还是太差,考场上想了巨久最后交的暴力。

核心思想:一个物品可以保存多天,这样无法存状态,所以转换为第一天买入,然后第二天立即卖出,在当天又立即买回,然后第三天又卖出……一直这样,和把一个物品保存 \(n\) 天是等价的,而且还好存状态。至于一个物品保存几天取决于最优决策。

定义 \(dp[i][j][k]\) 表示在第 \(i\) 天,当前考虑到第 \(j\) 个物品,手头有 \(k\) 元钱时最终可以达到的最大收益。那么答案就是 \(max\){\(dp[T][n][k]\)}。

分别考虑买或不买,容易写出方程 $$dp[i][j][k]=max(dp[i][j-1][k],dp[i][j-1][k+v[i][j]]+v[i+1][j]-v[i][j])$$
其中,\(v[i][j]\) 为第 \(i\) 天物品 \(j\) 的价值。

第一维显然可以滚掉,因为转移与天数无关。而每次转移只与前一个物品有关,所以第二维也可以滚掉,倒序枚举即可。

最终的方程为 $$dp[k]=max(dp[k],dp[k+v[i][j]]+v[i+1][j]-v[i][j])$$

Code:

#include<stdio.h>
#include<string.h>
#define N 107

template<class T>
inline void read(T &x){
    x=0;T flag=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')flag*=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    x*=flag;
}

int T,n,m,v[N][N],dp[N*N];
inline int max(int x,int y){return x>y? x:y;}
int main(){
    read(T),read(n),read(m);
    for(int i=1;i<=T;i++)
        for(int j=1;j<=n;j++)
            read(v[i][j]);
    int ans=m;
    for(int i=1;i<=T;i++){
        memset(dp,0,sizeof(dp));
        dp[ans]=ans;
        for(int j=1;j<=n;j++)
            for(int k=ans;k>=v[i][j];k--)
                dp[k-v[i][j]]=max(dp[k-v[i][j]],dp[k]+v[i+1][j]-v[i][j]);
        int ret=0;
        for(int k=0;k<=ans;k++)
            ret=max(ret,dp[k]);
        ans=ret;
    }
    printf("%d",ans);
}
posted @ 2020-03-03 12:30  Kreap  阅读(168)  评论(0编辑  收藏  举报