滑稽树前做游戏, 滑稽树后做交易

本文探讨了一种特殊的滑稽果购买场景,顾客sxd希望找到最长的连续滑稽果序列,使其喜爱程度之和为正。通过对原始数据的预处理和动态规划技巧,实现了高效算法解决这一问题。

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

题目描述
滑稽果被排成一列, poison 的 lsr 要求每个顾客只能买一段连续的区间。
sxd 来这里买滑稽果,他对每个滑稽果都有一个喜爱程度 Ai 是一个整数,-100≤Ai≤100,
并保证∑Ai <=2147483647, 最终的满意度为所有他买到的滑稽果的喜欢程度之和, 如果和
为正(不管是正多少, 只要大于 0 即可) , 则他满意了。
现在 sxd 想知道在他满意的条件下最多能买到多少滑稽果。
输入描述
第一行一个正整数 n, 表示 lsr 一共摘了 n 个滑稽果。
第二行 n 个整数, 每个整数 Ai 表示 sxd 第 i 个滑稽果的喜爱程度为多少。
输出描述
一行一个正整数 ans 表示在 sxd 满意的条件下最多能买到多少滑稽果
输入样例
5 0
0 -7 -6 1
输出样例
1
数据范围及提示
对于 30%的数据, n<=510^3
对于 60%的数据, n<=10^5
对于所有数据, n<=3
10^7
请注意本题的内存限制, 完成代码后请务必计算一下你程序的内存是否超限。
由于本题的输入过大, 请必须使用基于 fread 的输入模板, 见题目目录下的 fastIO.cpp
神奇的题目 奇妙的解法···这是一道神奇的题目
首先给出暴力解法

#include <iostream>
#include <cstdio>
#include <cmath>
#pragma GCC optimize(3)
using namespace std;

int    a[50000005],len[50000005];
int     sum[50000005];
int    maxlen;
inline char gc()
{
	static char buf[1<<12],*p1=buf,*p2=buf;
	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<12,stdin),p1==p2)?EOF:*p1++;
}

#define dd c = gc()
inline int read()
{
	static int x;
	x = 0;
	int dd;
	bool f = false;
	for(; !isdigit(c); dd)
		if(c == '-')
			f = true;
	for(; isdigit(c); dd)
		x = (x<<1) + (x<<3) + (c^48);
	if(f)
		x = -x;
	return x;
}
#undef dd
int main() {
	freopen("trade.in","r",stdin);
	freopen("trade.out","w",stdout);
	long  n;
	//scanf("%d",&n);
	n=read();
	for(int i=1;i<=n;i++)
	{
	    //scanf("%d",&a[i]);
        a[i]=read();
		sum[i]=sum[i-1]+a[i];
		for(int j=0;j<=i;j++)
	    {
	   	if(sum[i]-sum[j]>0&&i-j>maxlen) maxlen=i-j;
	    }
	}

	printf("%d",maxlen);
	return 0;
}

明眼人一看数据范围就知道
这肯定超时了
然后我也没思路了 再然后就是其他大佬的指导了

大佬说首先简化一下
把查询的时间复杂度降下来
求出从i到n范围内的最大值
这样就是一个有序的单调的数列了

for(int i=n;i>=1;i--)
{
  maxx[i]=max(maxx[i+1],sum[i]);
}

从左往右开始扫描
当右指针所在的最大值小于左指针所在的前缀和
那么表示右指针右边的值的和小于0符合条件是
右指针向右扫描
直到右指针所处位置的最大值小于等于左指针的前缀和
然后代码如下

    for(int l=1,r=1;l<=n&&r<=n;l++,r++){
		if(maxx[r]<=sum[l-1])
			continue;
		while(maxx[r]>sum[l-1]&&r<=n){
			r++;
		}
		ans=max(ans, r-l);
	}

最后总结一下就是

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

int    maxx[30000005];
int    sum[30000005];
int    ans=0;
inline char gc()
{
	static char buf[1<<12],*p1=buf,*p2=buf;
	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<12,stdin),p1==p2)?EOF:*p1++;
}

#define dd c = gc()
inline int read()
{
	static int x;
	x = 0;
	int dd;
	bool f = false;
	for(; !isdigit(c); dd)
		if(c == '-')
			f = true;
	for(; isdigit(c); dd)
		x = (x<<1) + (x<<3) + (c^48);
	if(f)
		x = -x;
	return x;
}
#undef dd
int main() {
	freopen("trade.in","r",stdin);
	freopen("trade.out","w",stdout);
	memset(maxx, -0x3f3f3f3f, sizeof(maxx));
	int   n;
	n=read();
	for(int i=1;i<=n;i++)
	{
        sum[i]=read();
		sum[i]+=sum[i-1];
	}
    for(int i=n;i>=1;i--)
    {
    	maxx[i]=max(maxx[i+1],sum[i]);
	}
    for(int l=1,r=1;l<=n&&r<=n;l++,r++){
		if(maxx[r]<=sum[l-1])
			continue;
		while(maxx[r]>sum[l-1]&&r<=n){
			r++;
		}
		ans=max(ans, r-l);
	}
	printf("%d",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值