首页 > 其他分享 >AcWing100 -- 差分 & 贪心

AcWing100 -- 差分 & 贪心

时间:2023-03-14 19:12:52浏览次数:45  
标签:AcWing100 -- 差分 修改 int abs 数组 我们 贪心

1. 题目描述

题目给定我们一个数组,我们每次可以对数组的一段区间加一或者减一,问我们,使得序列所有数字相等的最少操作次数以及方案个数



2. 思路

很容易想到差分,将题目转化为(假设数组下标从 \(1\) 开始),最少的操作次数,使得差分数组 s[2] ~ s[n] = 0 的最少操作次数,s[1] 就是最后数组的元素值。

注意到 s[1] 就是数组最后的值对求第二问的方案数很关键。

对于第一问,我们可以贪心的方式,在差分数组中,每次选取两个数,对一个数加一,对一个数减一。
但是这里需要注意两个边界情况,修改的数是 s[1]s[n+1]
为什么说是边界情况呢?先分析一下我们对原数组进行修改的几种情况:

  1. 修改的范围不包过头 [1] 和尾 [n],那么,在差分数组中,[L] >= 2[R] <= n
  2. 修改的范围包括头,但是不包括尾,那么在差分数组中,[L] == 1[R] <= n
  3. 修改的范围不包空头,但是包括尾,那么在差分数组中,[L] >= 2[R] == n + 1
  4. 修改的范围既包括头,又包括尾,那么在差分数组中,[L] == 1[R] == n + 1,但是修改整个数组毫无意义。

为什么要根据是否包括头和尾来划分修改的种类呢?相信你仔细看的话,应该可以从其对应于差分数组的修改看出端倪了!
当我们修改的范围从头开始,也就是包括头时,我们会修改 s[L]=s[1],我们前面提到过, s[1] 就是数组最后的元素值,它直接影响着方案数!
当我们修改的范围包括尾时,我们会修改 s[R]==n+1,而这对我们差分数组毫无影响。
由于修改整个数组毫无意义,并且我们希望修改的 s[2]~s[n] 使得其元素值都为 0,而 s[1] 是多少不用管,所以,我们只关心 s[2]~s[n]
因此,下面的差分数组就代指 s[2]~s[n]

  1. 修改差分数组中的两个数
  2. 修改差分数组的一个数,并且会修改头
  3. 修改差分数组的一个数

我们发现,我们每次要么修改一个数,要么修改两个数(一个加一,一个减一),因此,贪心的话,第一问就解决了!
我们设差分数组(s[2]~s[n])中正数之和为 \(p\),负数之和为 \(q\)
res1 = min(p, q) + abs(p - q);
其中,min(p,q) 定义修改 \(1\),每次修改一个正数和一个负数,abs(p-q) 对定修改 \(2\),每次修改一个数。
其实可以将上面的式子等价转换为: res1 = max(p,1);

对于第二问,我们前面不止一次提到过了,差分数组 s[1] 的值就是最后数组的元素,那么 s[1] 值可能的个数就是方案数。
我们前面对修改的划分也提到了,只有修改 \(2\) 会改变 s[1] 的值,那么方案数就取决于修改 \(2\) 的次数了!
由于修改 \(2\) 只会作用于 abs(p-q) 中,而修改 \(3\) 也可能作用于其中,所以 res2 = abs(p-q)+1

ref



3. 代码

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1e5 + 10;

int n, a[N], s[N];

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i ++ )   cin >> a[i];

    long long p = 0, q = 0;
    for(int i = 2; i <= n; i ++ )  
    {
        s[i] = a[i] - a[i - 1];
        if(s[i] > 0)    p += s[i];
        else if(s[i] < 0)   q -= s[i];
        else /* p == 0, ignore*/ ;
    }
    long long res1 = max(p, q);
    int res2 = abs(p - q) + 1;
    cout << res1 << endl << res2 << endl;
    
    return 0;
}

4. 惨痛的教训

题目数据为 1e5,假设所有数都是正数,那么 res1 肯定爆 int

标签:AcWing100,--,差分,修改,int,abs,数组,我们,贪心
From: https://www.cnblogs.com/ALaterStart/p/17215975.html

相关文章

  • NOI春季测试游记
    Day-20本来以为不能报名,但听说其他初中组织人参加,遂报名。某人试图21天学通C++Day-20~-2刷一些题,并学了大量新知识如DP。但是显然不够使我AKDayn(-15≤n≤-5)在......
  • 如何在AS中实现mysql查询并输出在视图上
    新建子线程启用mysqlnewThread(){@overridepublicvoidrun(){//在这里进行数据库调用}}.start(); handler简单使用方法hand1.sendEmptyMessage(i);//......
  • 上位机练习小项目(一)
    软件学习记录:(1)软件架构搭建分层架构:DAL、Models、View。目前view层存储页面与基本的业务逻辑。DAL层存放帮助类文件。Models层存放运行中使用的模型类。软件的项目结......
  • HDOJ 2071-2080
    2071MaxNumProblemDescriptionTherearesomestudentsinaclass,Canyouhelpteacherfindthehigheststudent. InputTherearesomecases.Thefirstli......
  • Linux网络服务:DNS域名服务系统
    DNS域名系统服务1.DNS介绍1.1什么是域名?域名(DomainName),简称域名、网域,是由一串用点分隔的名字组成的Internet上某一台计算机或计算机组的名称,用于在数据传输时标识计......
  • vscode 中运行 c# 代码?
    目前来看,只能运行,调试要用其它插件且需要配置,太复杂,不如用linqpad。使用插件CodeRunner,前提是先要安装scriptcs,这个还牵扯新旧版本的问题,最新版本名字改成了 dotnet-s......
  • Linux网络服务:DHCP
    网络服务-DHCP1.DHCP简介 DHCP(DynamicHostConfigurationProtocol,动态主机配置协议)是一个工作在应用层的局域网网络协议,数据传输时使用UDP不可靠传输协议工作,通常被应......
  • nvidia-smi
    nvidia-smi是nvidia的系统管理界面,其中smi是Systemmanagementinterface的缩写   GPU:**本机中的GPU编号(有多块显卡的时候,从0开始编号)图上GPU的编号是:0Fan:风扇......
  • 计算机组成原理第一章复习
    1、计算机发展史第一代 1946-1957电子管计算机第二代 1958-1964晶体管计算机第三代 1965-1971中小规模集成电路计算机第四代 1972-1990大规模和超大规模集......
  • derive layout
    https://www.cnblogs.com/pandamohist/p/13882020.html   #include"iostream"structB{virtualvoidf(){}uint64_tb;};structC{virtualvoidfc......