首页 > 其他分享 >「AcWing学习记录」区间问题

「AcWing学习记录」区间问题

时间:2023-01-03 23:04:18浏览次数:61  
标签:cnt 记录 int range 端点 Ans 区间 AcWing

AcWing 905. 区间选点

原题链接

给定 N 个闭区间 [ai,bi],请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。

输出选择的点的最小数量

位于区间端点上的点也算作区间内。

思路:

  1. 将每个区间按右端点从小到大排序
  2. 从前往后依次枚举每个区间
  • 如果当前区间中已经包含点,则直接pass
  • 否则,选择当前区间的右端点

证明:

  1. Ans ≤ cnt
    Ans 为正确答案(最小数量),而 cnt 为按照思路求解的结果,显然 Ans ≤ cnt。
  2. Ans ≥ cnt
    从前往后依次枚举每个区间时,如果当前区间的左端点严格大于当前记录的右端点,则 cnt++,即找到了 cnt 个互不相交的区间,也就是至少要选择 cnt 个点,Ans ≥ cnt 得证。
点击查看代码
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 1e5 + 10;

int n;
struct Range
{
    int l, r;
    bool operator< (const Range &rhs)const
    {
        return r < rhs.r;
    }
}range[N];

int main()
{
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
    {
        int l, r;
        scanf("%d%d", &l, &r);
        range[i] = {l, r};
    }
    
    sort(range, range + n);
    
    int res = 0, ed = -2e9;
    for(int i = 0; i < n; i++)
    {
        if(range[i].l > ed)
        {
            res++;
            ed = range[i].r;
        }
    }
    
    printf("%d\n", res);
    
    return 0;
}

AcWing 908. 最大不相交区间数量

原题链接

给定 N 个闭区间 [ai,bi],请你在数轴上选择若干区间,使得选中的区间之间互不相交(包括端点)。

输出可选取区间的最大数量

这题的思路和代码与上题完全一致。

证明:

  1. Ans ≤ cnt 反证法
    假设 Ans > cnt,这就意味着可以选择出来比 cnt 更多个互不相交的区间,也就是要选择至少 Ans 个点才能把所有的区间覆盖到,而实际上我们之前选择的这 cnt 个点就已经把所有的区间都覆盖到了,即每一个区间都至少包含一个我们选择出来的点,这与实际情况不符,Ans ≤ cnt 得证。
  2. Ans ≥ cnt
    Ans 为正确答案(最大数量),而 cnt 为按照思路求解的结果,显然 Ans ≥ cnt。

AcWing 906. 区间分组

原题链接

给定 N 个闭区间 [ai,bi],请你将这些区间分成若干组,使得每组内部的区间两两之间(包括端点)没有交集,并使得组数尽可能小。

输出最小组数

思路:

  1. 将每个区间按左端点从小到大排序
  2. 从前往后依次枚举每个区间,判断能否将其放到某个现有的组中 L[i] > Max_r
  • 如果不存在这样的组,则开新组,然后再将其放进去
  • 如果存在这样的组,将其放进去(在满足条件的组中任意挑一组),并更新当前组的 Max_r

证明:

  1. Ans ≤ cnt
    Ans 为正确答案(最小组数),而 cnt 为按照思路求解的结果,显然 Ans ≤ cnt。
  2. Ans ≥ cnt
    当枚举到第 cnt 个组时,即与前 cnt - 1 个组都有交集,此时 L[i] 一定大于每个组最右端区间的左端点(因为每个区间按左端点从小到大排序),同时小于等于每个组的 Max_r,所以一定会有 cnt 个区间存在交点 L[i],即至少需要 cnt 个组将已经枚举的区间完全分开,Ans ≥ cnt 得证。
    (L[i] 为第 i 个区间的左端点,其中第 i 个区间为新开的第 cnt 个组的第 1 个区间)
点击查看代码
#include<iostream>
#include<algorithm>
#include<queue>

using namespace std;

const int N = 1e5 + 10;

int n;
struct Range
{
    int l, r;
    bool operator< (const Range &rhs)const
    {
        return l < rhs.l;
    }
}range[N];

int main()
{
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
    {
        int l, r;
        scanf("%d%d", &l, &r);
        range[i] = {l, r};
    }
    
    sort(range, range + n);
    
    priority_queue<int, vector<int>, greater<int> > heap;
    for(int i = 0; i < n; i++)
    {
        auto r = range[i];
        if(heap.empty() || heap.top() >= r.l) heap.push(r.r);
        else
        {
            heap.pop();
            heap.push(r.r);
        }
    }
    
    printf("%d\n", heap.size());
    
    return 0;
}

AcWing 907. 区间覆盖

原题链接

给定 N 个闭区间 [ai,bi] 以及一个线段区间 [s,t],请你选择尽量少的区间,将指定线段区间完全覆盖。

输出最少区间数,如果无法完全覆盖则输出 −1。

思路:

  1. 将每个区间按左端点从小到大排序
  2. 从前往后依次枚举每个区间,在所有能覆盖 start 的区间中,选择右端点最大的区间,然后将 start 更新成右端点的最大值

证明:

  1. Ans ≤ cnt
    Ans 为正确答案(最小组数),而 cnt 为按照思路求解的结果,显然 Ans ≤ cnt。
  2. Ans ≥ cnt
    Ans 中的区间一定能用 cnt 中的区间替换,并且替换完的方案仍然是合法的,所以 cnt 中的区间一定是最优解,即 Ans ≥ cnt。
点击查看代码
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 1e5 + 10;

int n;
struct Range
{
    int l, r;
    bool operator< (const Range &rhs)const
    {
        return l < rhs.l;
    }
}range[N];

int main()
{
    int st, ed;
    scanf("%d%d", &st, &ed);
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
    {
        int l, r;
        scanf("%d%d", &l, &r);
        range[i] = {l, r};
    }
    
    sort(range, range + n);
    
    int res = 0;
    bool success = false;
    for(int i = 0; i < n; i++)
    {
        int j = i, r = -2e9;
        while(j < n && range[j].l <= st)
        {
            r = max(r, range[j].r);
            j++;
        }
        
        if(r < st)
        {
            res = -1;
            break;
        }
        
        res++;
        if(r >= ed)
        {
            success = true;
            break;
        }
        
        st = r;
        i = j - 1;
    }
    
    if(!success) res = -1;
    printf("%d\n", res);
    
    return 0;
}

标签:cnt,记录,int,range,端点,Ans,区间,AcWing
From: https://www.cnblogs.com/YuukiAsuna/p/17023048.html

相关文章

  • 【问题记录】【SpringBoot】【Jackson】SpringBoot返回的json结果,某个属性有值结果却
    1 问题描述代码如下:@DatastaticclassDemo{@JsonProperty(index=1)privateStringmenu;@JsonProperty(index=1)pri......
  • 2022年12月刷题记录
    2022年12月1日leetcode1779.找到最近的有相同X或Y坐标的点链接地址:https://leetcode.cn/problems/find-nearest-point-that-has-the-same-x-or-y-coordinate/题意:......
  • 2022年11月刷题记录
    2022年11月1日leetcode1662.检查两个字符串数组是否相等链接地址:https://leetcode.cn/problems/check-if-two-string-arrays-are-equivalent/题意:给你两个字符串数组......
  • CMAKE学习记录
    1.定义  CMAKE是一个开源、跨平台的编译、测试和打包工具,它使用比较简单的语言描述编译、安装的过程,输出Makefile或者project文件,再去执行构建。  当多人协同开发一......
  • 学习记录-Spring Boot Admin 监控应用
    SpringBootAdminSpringBootActuator提供了各种端点,SpringBootAdmin能够将Actuator中的信息进行界面化的展示,并提供实时报警功能。在微服务环境中,使用SpringB......
  • 双指针+位运算+离散化+区间合并
    双指针+位运算+离散化+区间合并双指针算法可以是两个指针分别指向两个序列,也可以是两个指针指向一个序列,维护一段区间核心思想:将\(O(n^2)\)优化到\(O(n)\)本质上就......
  • 记录一次项目中CEF版本的升级(二):CEF编译
    默认的发布版本是不支持mp4,mp3等音视频格式的,官方解释是说由于版权和各个国家法律问题。这就给我们造成了麻烦。必须得自己下载代码,修改,然后编译,才能支持音视频。官方构建......
  • acwing4644. 求和
    题目原题链接参考题解方法1思路求两两相乘的和,求a[i]与每个a[j]的乘积的和,就是求a[j]的和与a[i]的乘积所有先把所有数求和sum,然后让\(a[i]*(sum-a[i])\),枚举每一个......
  • 用VUE 搭建一个SSC网站全局记录
    1.准备数据库。2.搭建项目vue全家桶3.项目安装依赖###前端a.vuecreatevue-purhase ------创建项目名称b.npmiaxios-S  /网络请求c.npmiquerystring......
  • 2022.01.03 区间建仓352法
    区间建仓352法又称菱形建仓法提前做好规划以东财为例,个股占总仓位数不能超10%总仓位25万的话,东财应该最多2.5万,对应到19.27的股价,接近于1300股=10%1.352建仓法购......