CF1526C1 Potions (Easy Version)题解

本文介绍了一种利用贪心算法解决寻找数组中最长子序列的问题,该子序列要求其所有元素的前缀和不为负。通过建立优先队列,将元素取反入队并维护累加器,当累加器变为负数时,删除最小的负数,最终得到最长满足条件的子序列。代码实现中使用了C++的优先队列数据结构。

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

这篇题解可能会有重复的地方,但我会把我做这道题所学到的和所研究的分享给大家,建议新手观看。大佬跳过

首先,了解一下题目中出现的关键词:子序列和前缀和。

子序列

子序列就是在原来序列中找出一部分组成的序列。

要注意的是,子序列是由原来序列中符合条件的元素按从前往后的顺序添加到新序列中所组成的序列,顺序是不能变的。比如说有一个序列 12345 1 2 3 4 5 12345,它的子序列可以是 124 124 124,也可以是 135 135 135,但不可以是 231 231 231,也不可以是 342 342 342

前缀和

前缀和是一个数组的某个元素的下标之前(包括此元素)的所有数组元素的和。

这道题知道这些前缀和知识就足够了,如果还想了解更多,可以去这位大佬的博客学习:
https://www.cnblogs.com/-Ackerman/p/11162651.html#

知道了这些,就可以很轻松地把这道题切掉了~~

这道题的大体意思就是给出一个序列,求出最长子序列使得这个子序列的每一个元素的前缀和均不为负。

思路

这道题我用的是贪心,非负数一定要在这个子序列中,至于负数怎么选,要紧扣子序列定义来做,我们可以建一个优先队列,并按顺序依次将原序列的元素取反入队(优先队列优先弹出队列中数值大的元素),并且用一个累加器累加,当这个累加器变为负数时,弹出栈顶元素,其实就是当时最小的负数,如果子序列中有这个数,那么这个方案一定不是最优,所以必须舍弃,到最后,看一看舍弃了几个数,用原序列个数减去即为最终答案。

看数据范围,还是开 long long 比较保险。

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;
int n;
ll f[2010],tot,t,p,sum;
priority_queue<ll> q;//优先队列 
int main()
{
	scanf("%d",&n);
	tot=n;//先记录原序列个数 
	for(int i=1;i<=n;i++)
		scanf("%lld",&f[i]);
	for(int i=1;i<=n;i++){
		sum+=f[i];//累加器不断累加 
		q.push(-f[i]);//取反入队 
		if(sum<0){//累加器小于0,要删元素了 
			p=q.top();
			q.pop();
			p=-p;//变回原来的数值 
			sum-=p;//清除这个非最优选择 
			t++;//统计删除数字的个数 
		}
	}
	printf("%lld",tot-t);//总数减删除数字的个数即为答案 
	return 0;
}

完结撒花~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值