CF1779C Least Prefix Sum 题解
CF链接:Least Prefix Sum
Luogu链接:Least Prefix Sum
$ {\scr \color {CornflowerBlue}{\text{Solution}}} $
先来解释一下题意:
给定一个数组,问最少把多少个数变成相反数,使得$ \forall \cal{i}$,$ \sum_{k=1}^i a_k$ $ \le$ $ \sum_{k=1}^m a_k$
发现对于所有数据点,$ \cal{n} \le 2 \times 10^5$,说明需要 $ Ο(\cal{n \log n}) $ 或者 $ O(\cal{n}) $的算法。
分析一下题目,发现要分成$ \cal{i} > \cal{m}$ 与$ \cal{i} < \cal{m}$两种情况分类讨论
- 当 $\cal{i}$ $ > \cal{m}$时:
什么时候才能使$ \sum_{k=1}^i a_k$ $ \le$ $ \sum_{k=1}^m a_k$ 成立呢?
是不是只要使新加的每一段都小于等于0就行了?($ \sum_{k=m}^i a_k$ $ \le$ $ 0$)
也很好证明:一个数($ \sum_{k=1}^m a_k$)加上一个小于等于0的数($ \sum_{k={m+1}}^i a_k$),一定不大于原数。
- 当 $\cal{i}$ $ < \cal{m}$时:
同理,只要使后加的每一段都小于等于0就行了($ \sum_{k=i}^i a_k$ $ \ge$ $ 0$)
也很好证明:一个数($ \sum_{k=1}^i a_k$)加上一个大于等于0的数($ \sum_{k=i}^m a_k$),一定不小于原数。
而且,由于这两种情况类似(博主太懒),那就只考虑当 $\cal{i}$ $ > \cal{m}$的情况吧。
问题已经转化完了,接下来怎么办?
第一眼想到的是贪心。
设当前要取第$\cal{i}$个。
有一个不成熟的贪心:如果目前累加和加上$a_i$还是小于等于$0$的,就加上$a_i$,如果大于$0$了,就把$a_i$取反,$ ans+1$。
Hack数据
5 1
1 -1000 999 2 100
我们只要把999 变成-999就行了,但如果按上面贪心方法,我们要把2,100都改变!
那么贪心就不可以用了吗?
有个神奇的东西交叫反悔贪心!
简单说一下:对于当前不是最优的情况,留到后面重新选择。
我们肯定要让每次改变值后,获得综合最小的值,但当前的选择又不一定最有优。
我们可以用一个优先队列维护,到了每次要改的时候,从优先队列中选出一个收益最大(使目前累加和最大或最小)的值修改。
注意开$ \cal{long long}$并且清空优先队列!
Code(赛时代码,过丑见谅QwQ):
#include<bits/stdc++.h>
#define L long long
using namespace std;
L a[200005];
priority_queue<L,vector<L>,greater<L> > q;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
while(!q.empty()) q.pop();
int n,m,ans=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
if(n==1)
{
printf("0\n");
continue;
}
if(m==1)
{
L mu=0;
for(int i=m+1;i<=n;i++)
{
if(a[i]>=0) mu+=a[i];
else if(a[i]<0 && mu+a[i]>=0)
{
q.push(a[i]);
mu+=a[i];
}
else
{
ans++;
q.push(a[i]);
mu+=a[i];
mu-=2*q.top();
q.pop();
}
}
printf("%d\n",ans);
continue;
}
L mu=0;
for(int i=m+1;i<=n;i++)
{
if(a[i]>=0) mu+=a[i];
else if(a[i]<0 && mu+a[i]>=0)
{
q.push(a[i]);
mu+=a[i];
}
else
{
ans++;
q.push(a[i]);
mu+=a[i];
mu-=2*q.top();
q.pop();
}
}
while(!q.empty()) q.pop();
mu=0;
for(int i=m;i>=2;i--)
{
if(a[i]<=0) mu+=a[i];
else if(a[i]>0 && mu+a[i]<=0)
{
q.push(-a[i]);
mu+=a[i];
}
else
{
ans++;
q.push(-a[i]);
mu+=a[i];
mu+=2*q.top();
q.pop();
}
}
printf("%d\n",ans);
}
return 0;
}
CF1779C Least Prefix Sum 题解的更多相关文章
- 牛客网暑期ACM多校训练营(第十场)D Rikka with Prefix Sum (数学)
Rikka with Prefix Sum 题意: 给出一个数组a,一开始全为0,现在有三种操作: 1. 1 L R W,让区间[L,R]里面的数全都加上W: 2. 2 将a数组变为其前缀 ...
- [CF1204E]Natasha,Sasha and the Prefix Sums 题解
前言 本文中的排列指由n个1, m个-1构成的序列中的一种. 题目这么长不吐槽了,但是这确实是一道好题. 题解 DP题话不多说,直接状态/变量/转移. 状态 我们定义f表示"最大prefix ...
- 4.4 CUDA prefix sum一步一步优化
1. Prefix Sum 前缀求和由一个二元操作符和一个输入向量组成,虽然名字叫求和,但操作符不一定是加法.先解释一下,以加法为例: 第一行是输入,第二行是对应的输出.可以看到,Output[1] ...
- 牛客多校第十场-D- Rikka with Prefix Sum
链接:https://www.nowcoder.com/acm/contest/148/D来源:牛客网 Prefix Sum is a useful trick in data structure p ...
- Rikka with Prefix Sum(组合数学)
Rikka with Prefix Sum 题目描述 Prefix Sum is a useful trick in data structure problems. For example, giv ...
- Ural 1248 Sequence Sum 题解
目录 Ural 1248 Sequence Sum 题解 题意 题解 程序 Ural 1248 Sequence Sum 题解 题意 给定\(n\)个用科学计数法表示的实数\((10^{-100}\s ...
- Rikka with Prefix Sum
Rikka with Prefix Sum 题目 https://www.nowcoder.com/acm/contest/148/D 题目有三个操作 l到r都添加一个数 取一次前缀和 查询区间和 这 ...
- Codeforces Round #556 (Div. 2) - C. Prefix Sum Primes(思维)
Problem Codeforces Round #556 (Div. 2) - D. Three Religions Time Limit: 1000 mSec Problem Descripti ...
- LeetCode Continuous Subarray Sum 题解 同余前缀和 Hash表
文章目录 题意 思路 特殊情况k=0 Source Code 1 Source Code 2 题意 给定一个数组和一个整数k,返回是否存在一个长度至少为2的连续子数组的和为k的倍数. 思路 和上一篇博 ...
- Hdoj 1003.Max Sum 题解
Problem Description Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum ...
随机推荐
- .NET周报【10月第3期 2022-10-25】
国内文章 聊一聊被 .NET程序员 遗忘的 COM 组件 https://www.cnblogs.com/huangxincheng/p/16799234.html 将Windows编程中经典的COM ...
- R数据分析:扫盲贴,什么是多重插补
好多同学跑来问,用spss的时候使用多重插补的数据集,怎么选怎么用?是不是简单的选一个做分析?今天写写这个问题. 什么时候用多重插补 首先回顾下三种缺失机制或者叫缺失类型: 上面的内容之前写过,这儿就 ...
- 我要涨知识 —— TypeScript 常见面试题(一)
1.ts 中的 any 和 unknown 有什么区别? unknown 和 any 的主要区别是 unknown 类型会更加严格:在对 unknown 类型的值执行大多数操作之前,我们必须进行某种形 ...
- Linux备份文件加“时间”命令
好记性不如烂笔头,好用. date命令用于显示及设置系统的时间或日期,如何设置时间此处不再多说. date命令非常强大,可以将数据备份命令与date命令结合在一起使用,可以便捷的分辨出每个文件的备份时 ...
- java学习之spirng的aop
AOP技术 0x00前言 什么是AOP技术:在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的 ...
- 2022春每日一题:Day 8
题目:[HNOI2003]激光炸弹 二维前缀和,扫大小为m*m的矩形,取最大即可. 代码: #include <cstdio> #include <cstdlib> #incl ...
- vue 3.0 常用API 的介绍
vue3.0 生命周期 写法一 和vue2.x 一致 区别在于(beforeUnmount.unmount)名称不一样 写法二 在setup 中使用, 需要引用 如: import { onBefor ...
- 剖析一下"抢茅台"脚本底层逻辑
本文作者:梁东东 前言: 今天你撸茅台了么? 撸茅台已经成为社会现象,茶余饭后讨论的最佳实践 2022年双十一大促已经完美收官,兄弟姐妹克服种种困难与挑战.. 备战的会议室忙碌中带着紧张,当峰值过后的 ...
- apt-mirror 制作麒麟桌面版内网源
apt-mirror 制作麒麟桌面版内网源 一.修改apt软件安装源 1.修改source.list安装源 vi /etc/apt/sources.list 添加: deb http://archiv ...
- JAVA-面向对象之对象拷贝
Java 中的数据类型分为基本数据类型和引用数据类型.对于这两种数据类型,在进行赋值操作.用作方法参数或返回值时,会有值传递和引用(地址)传递的差别. Map对象 测试01-等号赋值: @Test p ...