前缀和(有意思的求区间值思想,重要思想!)

第4题     前缀和 查看测评数据信息

给一个有一个长度为n的数组a[1,2,...n]。

数组a的前缀和定义为s[i]=a[1]+a[2]+...+a[i](对于所有的1<=i<=n),规定s[0]=0

数组a的前缀和前缀最大值为max[i]=max(s[0],s[1],s[2],...s[i])(对于所有的0<=i<=n)

数组a的1类和谐度为为max[i]中不同的元素数量。

数组a的2类和谐度为所有a的所有排列中1类和谐度的种类数。

现在有一个长度为n的数组b[1,2,...n]。

给出q个询问,每个询问包含两个整数l,r,求b[l],b[l+1],b[l+2],...b[r]的2类和谐度为多少。

输入格式

 

第一行输入一个整数n(1<=n<=1e5),表示序列b的长度。

第二行输入n个整数b[i](1≤|b[i]|≤100).

接着输入一个整数q(1≤q≤1e5),表示询问次数。

然后q行,每行两个整数l,r(1≤l≤r≤n)。

部分数据n<=10

部分数据n<=100

 

输出格式

 

共q行,每行一个整数

 

输入/输出例子1

输入:

5

2 3 -1 -2 4

1

2 4

 

输出:

2

 

输入/输出例子2

输入:

10

1 2 5 -5 6 3 -1 6 3 -1

10

1 5

1 3

2 5

3 6

1 10

2 6

6 8

1 7

1 1

2 3

 

输出:

3

1

2

2

4

3

1

4

1

1

 

 

样例解释

 对于样例一,序列为[3,-1,2]。

其共六种排列,其1类和谐度有两种,分别为1和2,所以2类和谐度为2

 

 

题意


 

题意有点难懂,化简一下:

给一个区间,求这个区间的不同最大前缀和个数,然后对区间进行排列组合,继续上述操作,进行完这次操作后,求出每个区间排列后的结果,求有多少个不同的结果

例如:

下图a是原数组,共有2个排列组合方法

s[i]为a数组的前缀和,其中s[0]=0

Max[i]为s的前i个数的最大值,即这个区间的不同最大前缀和

第一个区间排列方法的不同最大前缀和的个数为2,记这个2为ans1,分别是{1,3},

第二个区间的不同最大前缀和的个数为2,,记这个2为ans2,分别是{2,3}

我们把答案加入集合,即  {ans1, ans2},发现就是 {2, 2},那么就是1种结果

 

 

做法


这里先引入一个结论,接下来会证明

求某种属性的种类数: 分别求答案上限,答案下限,上限-下限+1即为所求

 

那么对于这一题,我们要求出  Max  的上限,下限,那么我们求的不同的结果就是上限-下限+1

 

求上限


 

上限,我们想要求出尽量大的不同最大前缀和个数,我们还可以发现一个很直观的规律

如果一个区间的所有数字都>0(不会出现=0的情况,题目有说),那么这个区间的前缀和是一定是单调递增的,Max值也是单调递增的

所以这种情况下,Max不同的数量一定是最多的

 

但是如果区间中有负数呢?例如此图,代表Max数值大小走向

红色圈的数量就是此区间不同Max值的数量,我们发现,如果有一个负数在一个正数的后面,那么这个正数后面的一段区间的Max值都可能是同一个值

我们想要红色圈最多,那么就让这条线不断上升,即Max不断增加,正数用完了,就只能用负数了,会出现一个骤降,就相当于把所有负数安排在这个区间的最后一个正数后面,那么此时不同Max值最多

这里没有严谨证明,但是可以感性理解,如下图

 Max如果在中途减小了一个值,那么可能会上升不到原来的高度,那么就不如先在原来的高度上升后,再减少

 

上限的思路类似于贪心,思路:

正数在最前,负数在最后
ans:所有正数+1

因为Max[0]=0, 0也算一个ans,所以最后要+1

 

 求下限


 下限,我们想要求出尽量小的不同最大前缀和个数,那么可以由上限的一个小证明推出来:

 Max如果在中途减小了一个值,那么可能会上升不到原来的高度,那么就不如先在原来的高度上升后,再减少

 

那么我们考虑一会上升,一会下降

那么我们不就是想要下降的值大于上升的值吗?这样先上升,再下降,再上升的时候就回不到原来高度了

所以思路就出来了

用负数尽可能多的抵消正数,这里的抵消也是有要求的,要求最多,所以是把整个负数的值累加,然后把正数从小到大去抵消,这样才能最多

如果还有正数无法被抵消,那么就只能算进答案了

所以,ans:剩余正数+1

为什么加1?同上限,Max[0]=0,  0也算一个答案

 

 证明:在答案上下限中,中间的数是否合法?


 

为什么开头的结论一定是正确的?

由于作者是蒟蒻,不会严谨的证明,所以......我们构造一组数组看看

一个数列:1 2 -5 1 5 2

上限:6

下限:3

 我们看看中间数,4是可以取到的,如下图

 

  我们看看中间数,5是可以取到的,如下图

 好了,那么就证明完毕(比较简陋,哈哈哈)

 

 

 

Code


懂了思路代码是很简单的,不需要注释了,但是根据此题,本代码复杂度错误,是O(nq)的,会超时,好像是用莫队做,蒟蒻较菜,就只会这种做法了,比较也AC了,卡过去了

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;

int n, b[N], tmp[N], q, L, R, Max=0, Min=0, sum=0, cnt=0;
int main()
{
	scanf("%d", &n);
	for (int i=1; i<=n; i++) scanf("%d", &b[i]);
	
	scanf("%d", &q);
	while (q--)
	{
		Max=0, Min=0, sum=0, cnt=0;
		
		scanf("%d%d", &L, &R);
		for (int i=L; i<=R; i++)
		{
			if (b[i]<0) sum+=b[i];
			else if (b[i]>0) Max++;
			
			tmp[++cnt]=b[i];
		} 
		
		sort(tmp+1, tmp+1+cnt);
		for (int i=1; i<=cnt; i++)
		{
			if (tmp[i]<=0) continue;
			
			sum+=tmp[i];
			if (sum>=0) 
			{
				if (sum==0) Min=cnt-i;
				else Min=cnt-i+1;
				break;
			}
		}
		
		Max++, Min++;
		
		printf("%d\n", Max-Min+1);
	}
	return 0;
}

  

 

 

 

posted @ 2024-07-23 19:01  cn是大帅哥886  阅读(83)  评论(0)    收藏  举报