值钱的木头——前缀和思想
题目描述
现有一堆值钱的木头,它们排成一行,河神给了你一个可以改变一个区间内的木头的价值的机会(注意这个区间不能越过边界),因为这是河神给你的选择,因此你必须要把握这次机会,也就是说你必须改变一个区间内木头的价值。
当然你的目的是让这堆木头的总价值最高。
输入
第一行输入一个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;
}
人生最好的境界,是丰富的安静 |
---|