网教 7.蜜汁序列

该博客讨论了如何将一个蜜汁序列(前缀和非负的序列)划分成多个连续的蜜汁子序列,要求输出最多能分成多少段。通过分析前缀和,博主提出从最后一个数开始往前遍历寻找连续的正数或负数序列,当找到正数时,它自身即为一段,负数则需找到和大于0的连续序列。博主提醒注意数据范围可能导致的整数溢出问题,建议使用long long类型。最后给出了线性遍历的解决方案。

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

题目描述

传说中有一种蜜汁序列特别甜,所以爱吃甜的强渣学长特别喜欢这种序列。。。

蜜汁序列的定义如下:对于一个长度为n的序列a1,...,an,如果这个序列的n个前缀和全部非负,即若a1>=0,a1+a2>=0,...,a1+a2+...+an>=0,则称a序列是蜜汁序列。。。

显然一些蜜汁序列可以分成更多的蜜汁序列,例如1 2这个蜜汁序列可以分成1和2两个蜜汁序列,现在有一个长度为n的蜜汁序列,要求你把他分成若干连续的段,使得每段都是一个蜜汁序列,问最多可以分成多少段?

输入

多组用例,每组用例首先输入一个整数n表示给出的蜜汁序列长度,之后输入n个整数a1,a2,...,an表示该序列的n个元素,以文件尾结束输入

输出

对于每组用例,输出一个整数占一行,表示该序列最多可以分成多少个蜜汁序列

数据范围

用例不超过10组,1<=n<=10^6,-10^4<=ai<=10^4(i=1,2,...,n)

样例输入

1

1

3

1 2 3

样例输出

1

3


题解:

题目不难,读懂题目就能有个思路。问的是题目给的蜜汁序列中最多能划分成几个蜜汁序列。

因为数据范围非常大,所以如果每个数都是从a1开始一直往后数的话肯定会超时。但是注意到题目要求的是前缀和大于0,所以对于一个负数来说,要找到它所在的那个蜜汁序列,就必须要往前找,因为如果往后找的话肯定就已经不满足a1>=0了。如果有好几个负数连续,就需要从最后的那个负数开始往前倒。

一开始我写的是正序,后来就发现了问题:不知道遇到了a[n+1]>=0时是否要停止。就比如1 2 -1 -2 3 - 1 -2与2 2 -1 -2 2 -1 -2遇到第一个-1的时候不知道该不该停。所以就要从最后一个数往前数。

然后如何判断是否找到了蜜汁序列呢?方法是看这k个数总和是否大于0.如果遇到了正数,那么肯定它独自成一个序列。如果遇到了负数,就要往前找,直到这连续的k个数之和大于0为止。原因是a2--ak一定是负的,否则就不需要a1了;a3--ak也一定是负的……然后既然a1与a2--ak之和为正,且a3--ak为负,所以a1+a2也为正。以此类推……只要满足这k个数的和是正的,就能满足这是蜜汁序列。

有了如上思路,就能有一个线性遍历的算法了。但是还有一点没注意到,也就是这一点我WA了不止五发……

n是1e6,ai是1e4,稍有不慎就爆int。。。

所以必须要用long long啊orz

这序列果然很迷啊……

代码如下:

//因为一个long long 我wa了10法/微笑
#include<stdio.h>
#include<string.h>
int num[1000005];
int index = 0;

int main()
{
	int n;
	while (scanf("%d", &n) != EOF)
	{
		index = 0;
		int i = 0;
		for (i = 0; i < n; i++)
			scanf("%d", &num[i]);
		for (i = n - 1; i >= 0; i--)
		{
			if (num[i] < 0)
			{
				long long int sum = 0;
				while (sum + num[i]<0)
				{
					sum = sum + num[i];
					i--;
				}
			}
			index++;
		}
		printf("%d\n", index);
	}
	return 0;
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值