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. import cv2报错

    其实是没错的,不过有的python编译器对这个不太支持,把import cv2 改为import cv2.cv2 as cv2就行了.

  2. 18.-cookies和session

    一.会话定义 从打开浏览器访问一个网站,到关闭浏览器结束此次访问,称之为一次绘画 HTTP协议是无状态的,导致绘画状态难以保持 Cookies和session就是为了保持会话状态而诞生的两个存储技术 ...

  3. 学习Java AES加解密字符串和文件方法,然后写个简单工具类

    Reference Core Java Volume Ⅱ 10th Edition 1 对称加密 "Java密码扩展"包含了一个Cipher,它是所有密码算法的超类.通过getIn ...

  4. 一篇文章带你了解服务器操作系统——Linux简单入门

    一篇文章带你了解服务器操作系统--Linux简单入门 Linux作为服务器的常用操作系统,身为工作人员自然是要有所了解的 在本篇中我们会简单介绍Linux的特点,安装,相关指令使用以及内部程序的安装等 ...

  5. IP分类与子网划分

    1.IP地址的格式  每一类地址都由两个固定长度的字段组成: (1)网络号 net-id:它标志主机(或路由器)所连接到的网络 (2)主机号 host-id:它标志该主机(或路由器).   最大可指派 ...

  6. Codeforces Round #802 (Div. 2)C. Helping the Nature(差分)

    题目链接 题目大意: 给你一个有n个元素的数组a,你可以通过一下三种操作使数组的每一个值都为0: 选择一个下标i,然后让a[1],a[2]....a[ i ] 都减一; 选择一个下标i,然后让a[i] ...

  7. JS数据结构与算法-概述

    JS数据结构与算法概述 数据结构: 计算机存储, 组织数据的方式, 就像锅碗瓢盆 算法: 一系列解决问题的清晰指令, 就像食谱 两者关系: 程序 = 数据结构 + 算法 邂逅数据结构与算法 什么是数据 ...

  8. vue传值

    在vue 中组件间的传参是必不可少的,下面说下几种传参方式 1.父组件传值给子组件,首先父组件发送的形式是用bind(用缩写:)绑定值到子组件身上.然后子组件用属性props接收 2.子组件传值父组件 ...

  9. Go语言核心36讲19

    你好,我是郝林,今天我们继续分享go语句执行规则的内容. 在上一篇文章中,我们讲到了goroutine在操作系统的并发编程体系,以及在Go语言并发编程模型中的地位和作用等一系列内容,今天我们继续来聊一 ...

  10. 10 STL-list

    ​ 重新系统学习c++语言,并将学习过程中的知识在这里抄录.总结.沉淀.同时希望对刷到的朋友有所帮助,一起加油哦!  生命就像一朵花,要拼尽全力绽放!死磕自个儿,身心愉悦! 写在前面,本篇章主要介绍S ...