首页 > 其他分享 >ACWing 4480 -- 二分&&双指针&&思维

ACWing 4480 -- 二分&&双指针&&思维

时间:2022-10-26 12:55:28浏览次数:95  
标签:right -- ++ 垃圾桶 int 4480 && INF left

题目描述

倒垃圾

思路

其实就是思维题,题意很简单,找到一个居民左侧和右侧(如果存在的话)的垃圾桶中最近的那个垃圾桶,然后让那个垃圾桶的计数器加一。
从题目中挖掘的性质:左侧的垃圾桶就是居民左侧位置最大的那个,而右侧的垃圾桶就是居民右侧的位置最小的那个。由于题目给定垃圾桶的位置升序(即使无需我们也可以排序),很容易想到二分,我们只需要枚举每个居民,然后两次二分分别找到左侧和右侧的垃圾桶的位置就可以了。
但是这里有很多时间优化(一次二分其实就可以)和细节问题(二分边界处理--哨兵)。

一次二分:
由于右侧的那个垃圾桶是居民右侧位置最小的垃圾桶,那么该垃圾桶的前一个垃圾桶一定是居民左侧位置最大的垃圾桶(如果存在的话)。

哨兵
前面一直提到,如果垃圾桶存在的话。是因为存在两种边界情况:(题目给定垃圾桶至少一个。)

  1. 一个居民位于所有垃圾桶的左侧,因此不存在它右侧的垃圾桶。
  2. 一个居民位于所有垃圾桶的右侧,因此不存在它左侧的垃圾桶。

所以说为了二分的时候简单一些,我们可以分别在最左侧和最右侧设置两个哨兵。
但是这两个哨兵的位置该取多少呢?这个最好不要凭空想象。
我们可以从二分的语句里面去观察:由于我们需要比较左侧垃圾桶和右侧垃圾桶到居民的距离那个更小。
即:\(right - cur\) 与 \(cur - left\) 的那个值更小。
当我们处于边界情况的时候,我们肯定不希望取到我们的哨兵。所以说:

  1. 处于边界情况1,即不存在右侧的垃圾桶,此时 \(right\) 取得哨兵的值,假设为 \(val\)。我们要保证:\(val - cur > cur - left\) 恒成立。因此 \(val > 2 *cur\),由于 \(cur\) 最大为 \(10^9\),因此 \(val = 2 * 10^9\)

代码1

两边扫描优化未优化空间版本

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

using namespace std;

typedef pair<int, int> PII;

const int N = 2e5 + 10, INF = 2e9;

int n, m, a[N];
bool st[N];
PII l[N], r[N];
int ans[N];

int main()
{
    cin >> n >> m;
    for(int i = 0; i < n + m; i ++ )    cin >> a[i];
    for(int i = 0; i < n + m; i ++ )    cin >> st[i];
    
    // 从左往右扫描
    int left_max = INF, left_pos = -1; // 哨兵
    for(int i = 0; i < n + m; i ++ )
    {
        if(st[i] == 0) 
        {
            if(left_max == INF) l[i] = {INF, m + n + 1}; // 避免爆减法爆int
            else    l[i] = {a[i] - left_max, left_pos};
        }
        else left_max = a[i], left_pos = i;
    }
    
    // 从右向左扫描
    int right_min = INF, right_pos = -1;
    for(int i = n + m - 1; i >= 0; i -- )
    {
        if(st[i] == 0)
        {
            if(right_min == INF)    r[i] = {INF, m + n + 1};
            else    r[i] = {right_min - a[i], right_pos};
        }
        else right_min = a[i], right_pos = i;
    }
    
    for(int i = 0; i < n + m; i ++ )
    {
        if(st[i] == 0)
        {
            if(l[i].first <= r[i].first)    ans[l[i].second] ++ ;
            else    ans[r[i].second] ++ ;
        }
    }
    
    for(int i = 0; i < n + m; i ++ )
        if(st[i])
            cout << ans[i] << ' ';
    cout << endl;
    
    return 0;
}

代码2

两边扫描优化空间版

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

using namespace std;

const int N = 2e5 + 10, INF = 2e9;

int n, m, a[N];
bool st[N];
int l[N], r[N];
int ans[N / 2];

int main()
{
    cin >> n >> m;
    for(int i = 0; i < n + m; i ++ )    cin >> a[i];
    for(int i = 0; i < n + m; i ++ )    cin >> st[i];
    
    // 从左往右扫描
    int left_max = INF; // 哨兵
    for(int i = 0; i < n + m; i ++ )
    {
        if(st[i] == 0) 
        {
            if(left_max == INF) l[i] = INF; // 避免爆减法爆int
            else    l[i] = a[i] - left_max;
        }
        else left_max = a[i];
    }
    
    // 从右向左扫描
    int right_min = INF;
    for(int i = n + m - 1; i >= 0; i -- )
    {
        if(st[i] == 0)
        {
            if(right_min == INF)    r[i] = INF;
            else    r[i] = right_min - a[i];
        }
        else right_min = a[i];
    }
    
    int idx = 0;
    for(int i = 0; i < n + m; i ++ )
    {
        if(st[i] == 0)
        {
            if(l[i] <= r[i])    ans[idx] ++ ;
            else    ans[idx + 1] ++ ;
        }
        else idx ++ ;
    }
    
    for(int i = 1; i <= m; i ++ )   cout << ans[i] << ' ';
    cout << endl;
    
    return 0;
}

代码3

二分

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

using namespace std;

typedef long long LL;

const int N = 100010, INF = 1e9 + 1e9;

int n, m, ans[N];
int c[N << 1], a[N], b[N];

int main()
{
    cin >> n >> m;
    for(int i = 0; i < n + m; i ++ )    cin >> c[i];
    for(int k = 0, i = 0, j = 0; k < n + m; k ++ ) 
    {
        bool t; cin >> t;
        if(t)   b[ ++ j ] = c[k];   // 这里是先++是为了空位0放置哨兵
        else    a[i ++ ] = c[k];
    }
    
    /* 哨兵
        因为存在一个居民左侧没有垃圾桶或者右侧没有垃圾桶的情况,所以在二分的时候我们要设置一个边界
       但是为啥设置为 2e9 呢?
       
    */
    
    b[0] = -INF, b[m + 1] = INF;
    for(int i = 0; i < n; i ++ )
    {
        int l = 0, r = m + 1, pos = a[i];
        while(l < r)
        {
            int mid = l + r >> 1;
            if(b[mid] >= pos)   r = mid;
            else    l = mid + 1;
        }
        // 由于 r/l 是 i 右侧最近的,那么 r-1 的位置必然是 i 左侧最近的
        if((LL)pos - b[r - 1]<= (LL)b[r] - pos) // 这里要留意是否会溢出
            ans[r - 1] ++ ;
        else    ans[r] ++ ;
        
    }
    for(int i = 1; i <= m; i ++ )   cout << ans[i] << ' ';
    cout << endl;
    return 0;
}

代码4

双指针

标签:right,--,++,垃圾桶,int,4480,&&,INF,left
From: https://www.cnblogs.com/ALaterStart/p/16827943.html

相关文章

  • 【华为安全招聘】Windows内核开发工程师
    Windows内核开发工程师职责描述:1、公司产品的EDR底层C/C++开发。2、Windows内核相关的功能编码实现与维护。3、Windows内核相关的技术调研,原理分析。 任职要求:1、......
  • 找工作那会儿
    满打满算出来三年了,想想变了些什么。嗯~,是-混的越来越差了。哈哈哈哈,还记得刚出来那会,那是一个青涩啊,姿态很低,脸上的笑容像挤出来一样,就像是一个孩子笨拙的学着市侩。......
  • NGFW-虚拟系统与站点建立IPSec
    一,环境简介1.1拓扑图   1.2桥接虚拟网卡1.MGMT_PC   2.PC1   3.Server1   4.Internet   1.3实验需求在FW1上配置虚拟系统,并为......
  • 假如问:你是怎样优化Vue项目的,该怎么回答
    我们在开发Vue项目时候都知道,在vue开发中某些问题如果前期忽略掉,当时不会出现明显的效果,但是越向后开发越难做,而且项目做久了就会出现问题,这就是所说的蝴蝶效应,这样后期的......
  • go 课程表
    目录课程表项目工程Demo简化版(一)课程表项目工程Demo简化版(一)描述:主要讲了cmdb的基础框架,结构体,后端api的构建,怎么读取配置文件,日志的库的使用等。还有比如http调用s......
  • IfcTrimmingSelect
    IfcTrimmingSelect类型定义IfcTrimmingSelect允许在两种修剪曲线的方式之间进行选择。 注:定义符合ISO/CD10303-42:1992此选择类型标识修剪参数曲线的两种可能方法;通......
  • java8 Optional使用总结
    原文地址:https://www.cnblogs.com/kingsonfu/p/11009574.html【前言】 java8新特性java8函数接口java8lambda表达式Java8时间日期使用 java8推出的Optional的......
  • 2022“杭电杯”中国大学生算法设计超级联赛(10)1001 // 最大流
    题目来源:2022“杭电杯”中国大学生算法设计超级联赛(10)1001-WinnerPrediction题目链接:Problem-7244(hdu.edu.cn)题意给定\(T\)组案例。对于每组案例:给定人数......
  • 实验7:基于REST API的SDN北向应用实践
    目录一、实验目的二、实验环境三、实验要求(一)基本要求(二)进阶要求四、个人总结一、实验目的1.能够编写程序调用OpenDaylightRESTAPI实现特定网络功能;2.能够编写程序调......
  • Java知识10 变量类型【多测师】
    类变量(静态变量):独立于方法之外的变量用static修饰实例变量:独立于方法之外的变量没有static修饰//必须先创建一个对象实例化局部变量(类方法中的变量):类的方法中的变量......