E. The Human Equation(前缀和与差分数组)

文章讨论了一个关于序列操作的问题,目标是通过选取序列中的数并进行正负交替的操作,使整个序列变为全零。首先提出了一个初步的解决方案,但发现可能会导致超时。然后引入了前缀和数组的概念,解释了其优势在于能方便地进行加一和减一的操作。通过计算前缀和数组的最大值和最小值之差,可以得到最小的操作次数。代码示例展示了如何实现这一算法。
摘要由CSDN通过智能技术生成

在这里插入图片描述
嘤,总算过了
题目大意:可以从一个序列中按照顺序(可间断)选出一堆数,选出的这些数可以做以下操作:

  • 奇数位置 + 1 +1 1,偶数位置 − 1 - 1 1
  • 偶数位置 + 1 +1 1,奇数位置 − 1 - 1 1

直到整个序列变成全 0 0 0,停止。问整个过程所需要的最小操作次数

这个题我一开始想的是就用原数组做,构造出一个最长的正负交错的序列,比如现在栈里面如果有一个负数,那就应该在接收一个正数,如果再遇到一个负数就和栈里的负数比较,哪个小要哪个。以栈中最小的数对所有数进行处理,重复上述过程直到所有元素为 0 0 0.这个过程复杂度取决于元素的大小。但是如果考虑这个序列:
− 1 , 2 , − 3 , 4 , − 5 , . . . . -1,2,-3,4,-5,.... 12345....这样的序列一定会超时,如果考虑处理完栈中的元素对其清0,下次操作未必是最长的(未必最优)

下面的思路参考文章:
文章1
文章2

求一个序列的前缀和数组,那么如果原来的数组全 0 0 0就应该等价于前缀和数组全0.为啥要转换成前缀和数组?他有这样的好处,我们来看:
由于是在原序列中可以按照顺序随意间隔取数,转换在前缀和数组就是随意 + 1 , − 1 +1,-1 +11。(这个随意不是指 + 1 , − 1 +1,-1 11同时进行,而是指 + 1 +1 +1操作可以随意进行, − 1 -1 1操作可以随意进行。)而原数组相当于是前缀和数组的差分数组(差分数组介绍:点我)所以在前缀数组中 + 1 +1 +1,在差分数组中会自动弄出一个 + 1 , − 1 +1,-1 +1,1
(前后: a , b , c ; a,b,c; a,b,c;差分数组: a , d e l t a 1 , d e l t a 2 ; a,delta1,delta2; a,delta1,delta2;
a , b + 1 , c ; a,b+1,c; a,b+1,c;差分数组: a , d e l t a 1 + 1 , d e l t a 2 − 1 a,delta1+1,delta2-1 a,delta1+1,delta21)
我们假设对前缀数组中的元素是这样操作的:

1,0,0,1,0,0,1

则在原数组中是:

1-101-101(符合原要求)

如果在前缀数组中这样做:

11

原数组:

10

这样的话,只要计算出前缀和的最大值和最小值就可以了, 最大值 − 最小值 最大值-最小值 最大值最小值一定是最小的操作次数,不过要注意初始最大值和最小值为0.如果全都是负数的话,那么最优操作是将最小负数提上来。 最大值 − 最小值 最大值-最小值 最大值最小值是在最大值为正数,最小值为负数的情况下成立的,为了把正数拉下来,把负数抬上去。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define min(a,b) (a<b)?a:b
#define max(a,b) (a>b)?a:b
typedef long long ll;
const int length = 2e5 + 5;
ll num[length];
ll qianzhui[length];
int main(void)
{
	int t;
	scanf_s("%d", &t);
	for (int i = 0; i < t; i++)
	{
		int n;
		scanf_s("%d", &n);
		ll min1 = 0;
		ll max1 = 0;
		for (int i = 0; i < n; i++)
		{
			scanf_s("%lld", &num[i]);
			if (i == 0)
			{
				qianzhui[i] = num[i];
			}
			else
				qianzhui[i] = qianzhui[i - 1] + num[i];
			min1 = min(min1, qianzhui[i]);
			max1 = max(max1, qianzhui[i]);
		}
		printf("%lld\n", max1 - min1);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值