洛谷P2858

这是一篇关于洛谷P2858题目的解析,讨论了一道关于区间动态规划的题目。文章介绍了约翰卖零食的故事,零食的价值会随着时间增长而增加。约翰的目标是最大化最终收益。通过分析,作者提出了一种动态规划解决方案,不需要暴力搜索,而是通过计算区间长度和零食价值的变化来确定最大收益。AC代码也一同给出。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

还是一道区间dp题目。翻译如下

 

约翰经常给产奶量高的奶牛发特殊津贴,于是很快奶牛们拥有了大笔不知该怎么花的钱.为此,约翰购置了N(1≤N≤2000)份美味的零食来卖给奶牛们.每天约翰售出一份零食.当然约翰希望这些零食全部售出后能得到最大的收益.这些零食有以下这些有趣的特性:

•零食按照1..N编号,它们被排成一列放在一个很长的盒子里.盒子的两端都有开口,约翰每

天可以从盒子的任一端取出最外面的一个.

•与美酒与好吃的奶酪相似,这些零食储存得越久就越好吃.当然,这样约翰就可以把它们卖出更高的价钱.

•每份零食的初始价值不一定相同.约翰进货时,第i份零食的初始价值为Vi(1≤Vi≤1000).

•第i份零食如果在被买进后的第a天出售,则它的售价是vi×a.

Vi的是从盒子顶端往下的第i份零食的初始价值.约翰告诉了你所有零食的初始价值,并希望你能帮他计算一下,在这些零食全被卖出后,他最多能得到多少钱.

 

 

我们每次选择的时候都只会选一个开头或者结尾,之后剩下的所有零食价值增加一倍,如果,第一眼看一下肯定就是一个dfs暴力搜索,但是感觉算了算复杂度,并没有办法过掉,那么我们想一下最后被拿出的食物肯定价值是 原来的 n 倍了,而且每次取出一个零食,剩下的零食价值也会以区间的形式增值,那么我们不如列一个这样的dp

dp[ i ] [ j ] 代表 (i , j) 区间最大价值,那么我们想一下每次只会取走上边一个或者下边一个

那么则有 dp[ i ] [ j ] = max( dp[ i + 1] [ j ] + val [ i ] * cnt(当前第几次取这个食物) , dp[ i ] [ j - 1 ] + val [ j ] * cnt )

但是观察我们发现了这样一个事情,就是 既然知道 i j 那么剩余长度就知道了,既然剩余长度知道了,那么 

cnt = n - ( j - i ) 

那么我们不一定需要枚举结尾 i j,可以枚举长度就行了啊。而且 cnt 还被很容易的算出来了。

当然为避免特殊情况,我们对于每单个点的最大价值当然就是 n * val [ i ] 了。

 

以下是 AC 代码

 

 

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 2e4 + 5;
int dp[maxn][maxn];
int num[maxn];
int main()
{
    int n;
    scanf("%d", &n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&num[i]);
        dp[i][i] = num[i] * n;
    }
    for(int l=1;l<=n;l++)
    {
        for(int i=1;(i + l)<=n;i++)
        {
            int j = i + l;
            int cnt = n - l;
            dp[i][j]=max(dp[i+1][j] + num[i] * cnt, dp[i][j-1] + num[j] * cnt );
        }
    }
    printf("%d\n",dp[1][n]);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值