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 题解的更多相关文章

  1. 牛客网暑期ACM多校训练营(第十场)D Rikka with Prefix Sum (数学)

    Rikka with Prefix Sum 题意: 给出一个数组a,一开始全为0,现在有三种操作: 1.  1 L R W,让区间[L,R]里面的数全都加上W: 2.  2     将a数组变为其前缀 ...

  2. [CF1204E]Natasha,Sasha and the Prefix Sums 题解

    前言 本文中的排列指由n个1, m个-1构成的序列中的一种. 题目这么长不吐槽了,但是这确实是一道好题. 题解 DP题话不多说,直接状态/变量/转移. 状态 我们定义f表示"最大prefix ...

  3. 4.4 CUDA prefix sum一步一步优化

    1. Prefix Sum 前缀求和由一个二元操作符和一个输入向量组成,虽然名字叫求和,但操作符不一定是加法.先解释一下,以加法为例: 第一行是输入,第二行是对应的输出.可以看到,Output[1] ...

  4. 牛客多校第十场-D- Rikka with Prefix Sum

    链接:https://www.nowcoder.com/acm/contest/148/D来源:牛客网 Prefix Sum is a useful trick in data structure p ...

  5. Rikka with Prefix Sum(组合数学)

    Rikka with Prefix Sum 题目描述 Prefix Sum is a useful trick in data structure problems. For example, giv ...

  6. Ural 1248 Sequence Sum 题解

    目录 Ural 1248 Sequence Sum 题解 题意 题解 程序 Ural 1248 Sequence Sum 题解 题意 给定\(n\)个用科学计数法表示的实数\((10^{-100}\s ...

  7. Rikka with Prefix Sum

    Rikka with Prefix Sum 题目 https://www.nowcoder.com/acm/contest/148/D 题目有三个操作 l到r都添加一个数 取一次前缀和 查询区间和 这 ...

  8. Codeforces Round #556 (Div. 2) - C. Prefix Sum Primes(思维)

    Problem  Codeforces Round #556 (Div. 2) - D. Three Religions Time Limit: 1000 mSec Problem Descripti ...

  9. LeetCode Continuous Subarray Sum 题解 同余前缀和 Hash表

    文章目录 题意 思路 特殊情况k=0 Source Code 1 Source Code 2 题意 给定一个数组和一个整数k,返回是否存在一个长度至少为2的连续子数组的和为k的倍数. 思路 和上一篇博 ...

  10. 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 ...

随机推荐

  1. 10.-ORM-基础字段及选项

    一.ORM-基础字段及选项 任何关于表结构的修改,务必在对应模型类上修改 例如 给 books_book表添加一个info字段 varchar(100) 1.在模型中添加对应的类属性 2.执行数据库迁 ...

  2. 上传数据、下载模板文件解决方案(前端:antd;后端:.Net Core WebAPI)

    一.Excel 模板下载 通过静态文件下载. 将模板文件放在根目录的 public 文件夹下备用. 下载事件方法如下:(通过临时生成一个 a 标签,触发后再移除) downLoadExcelModel ...

  3. Sublime Text 修改默认语言为Python

    Sublime Text 3 修改默认语言为Python 步骤如下 英文:Tools - Developer - New Plugin 中文:工具 - 插件开发 - 新建插件 清空原来内容,用下面的代 ...

  4. Python基础部分:8、for循环和range的使用

    目录 一.while循环补充说明 1.死循环 2.嵌套及全局标志位 二.for...循环 1.for...循环特点 2.for...循环语法结构 三.range方法 1.什么是range 2.不同版本 ...

  5. 关于ASP.NET Core WebSocket实现集群的思考

    前言 提到WebSocket相信大家都听说过,它的初衷是为了解决客户端浏览器与服务端进行双向通信,是在单个TCP连接上进行全双工通讯的协议.在没有WebSocket之前只能通过浏览器到服务端的请求应答 ...

  6. nginx性能监控

    nginx自带监控模块,需要在nginx编译安装时加入监控模块. 1. 编译安装时加入监控模块 ngin编译安装时,加入编译参数为:--with-http_stub_status_module.如下所 ...

  7. 2022春每日一题:Day 35

    题目:[NOI Online #1 提高组] 冒泡排序 看到范围这么大,求逆序对,有修改,估计也只能树状数组了,考查冒泡排序性质,排第i次冒泡排序,总逆序对个数会减少i的逆序对个数,然后交换两个数,他 ...

  8. java:绘制图形

    java绘图类:Graphics类 绘图是高级程序中必备的技术,在很多方面都能用到,如:绘制闪屏图片,背景图片和组件外观等. 1.Graphics类 Graphics类是所有图形上下文的抽象基类,Gr ...

  9. 微服务---Dubbo+Zookeeper

    dubboAdmin客户端 --监控 && 启动 Zookeeper 客户端 --注册中心 生产者: <?xml version="1.0" encoding ...

  10. 【每日一题】【栈】2022年2月2日-NC40 两个链表生成相加链表

    描述 假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数. 给定两个这种链表,请生成代表两个整数相加值的结果链表. 答案:栈 import java.util.*; /* ...