值钱的木头——前缀和思想

这篇博客探讨了一种值钱的木头问题,其中可以通过改变一个区间内的木头价值来最大化总价值。博主介绍了两种方法来解决这个问题,一是滚动区间的思想,二是利用前缀和的优化方法。通过举例和AC代码,解释了如何利用前缀和快速求解区间修改问题,以找到最大价值。
摘要由CSDN通过智能技术生成

题目描述
现有一堆值钱的木头,它们排成一行,河神给了你一个可以改变一个区间内的木头的价值的机会(注意这个区间不能越过边界),因为这是河神给你的选择,因此你必须要把握这次机会,也就是说你必须改变一个区间内木头的价值。
当然你的目的是让这堆木头的总价值最高。
输入
第一行输入一个T(T <= 5),表示测试数据总数。
接下来2*T行,每组数据有2行。
每组数据第一行首先输入一个n(n <= 100000),接下来输入n个整数,分别表示这些木头的价值(-1000<=木头价值<=1000)
每组数据第二行输入两个整数x,y,其中x表示可以改变的区间的大小,y表示你可以把这个区间内的木头价值变为y(1<= x <= n,-1000<=y<=1000)
输出
你需要输出你所能获得的最大价值(这个价值可能为负数,表明你可能被河神给坑了)
样例输入
1
5
2 -5 -5 23 -11
1 3
样例输出
18
提示
显然你只需要把-11改为3就可以得到最大价值18。

ps:

初次遇见前缀和的题目,虽然事后看完大佬的题解来补题,但是感觉前缀和思想挺简单的,如果还记得的话,那么应该是高中(初中)就有类似的题目。

方法一:
滚动区间
1.首先要明确题目的意思,题目说可以把任意区间内的元素替换为y,那么显然,替换后的区间价值就是x*y,在中学我们已经学过类似的思想,所以我们只需要知道替换前的价值,就可以知道替换后这堆木头的总价值。
2.首先设all是木头初始价值和,a是替换前区间价值,b是替换后区间价值,替换后木头总价值和为all-a+b,在这里我举个例子:all=4,a=-3,b=4,替换后我们增大了b-a,所以加上原先的就是all-a+b;
3.我们可以假设这个区间长度为2,那么就有12 ,23, 34, 45 …可能,我们把区间看成盒子,这个盒子从左往右移动,依次装入每个元素,但是盒子只能装两个,所以在装下一个之前我们就要把最前面那个丢弃(减去),这样我们就可以计算出所有的长度为2区间,我们只要计算替换之后的总价值就行,取最大的输出,这样就可以解决题目了

AC代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int s[maxn];
int main()
{
   int a, n, t, ans, x, y, b, all;
   scanf("%d", &t);
   while (t--)
   {
      all = 0;
      scanf("%d", &n);
      for (int i = 1; i <= n; ++i)
      {
         scanf("%d", &s[i]);
         all += s[i];
      }
      scanf("%d%d", &x, &y);
      int a = 0, b = x * y;
      for (int i = 1; i <= x; ++i)
         a += s[i];
      ans = all - a + b;
      for (int i = x + 1; i <= n; ++i)
      {                 //前面提到的盒子思想
         a += s[i];     //装入下一个
         a -= s[i - x]; //减去最前面的
         ans = max(ans, all - a + b);
      }
      printf("%d\n", ans);
   }
   return 0;
}

方法二:
前缀和思想
其实感觉上下两个代码思想很类似,但是前缀和最大的有点就是极大的加快了代码的运行速度,大大缩短了时间
1.如果数组1,2,3,4,5,求前缀和,我们用另外一个数组来储存,那么就是1,3,6,10,15;
2.如果我们想求出i-j之间的和,只需要用pre[j]-pre[i-1],就可以得出

AC代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int s[maxn], pre[maxn];
int main()
{
    int n, b, a, ans, all, t, x, y;
    scanf("%d", &t);
    while (t--)
    {
        all = 0;
        scanf("%d", &n);
        memset(pre, 0, sizeof(pre));
        for (int i = 1; i <= n; ++i)
        {
            scanf("%d", &s[i]);
            all += s[i];
        }
        scanf("%d%d", &x, &y);
        for (int i = 1; i <= n; ++i)
            pre[i] = pre[i - 1] + s[i];
        b = x * y;
        ans = all - pre[x] + b;
        for (int i = x + 1; i <= n; ++i)
            ans = max(ans, all - pre[i] + pre[i - x] + b);
        printf("%d\n", ans);
    }
    return 0;
}
人生最好的境界,是丰富的安静
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值