《算法竞赛·快冲300题》每日一题:“浇水”

news2024/7/4 6:34:19

算法竞赛·快冲300题》将于2024年出版,是《算法竞赛》的辅助练习册。
所有题目放在自建的OJ New Online Judge。
用C/C++、Java、Python三种语言给出代码,以中低档题为主,适合入门、进阶。

文章目录

  • 题目描述
  • 题解
  • C++代码
  • Java代码
  • Python代码

浇水” ,链接: http://oj.ecustacm.cn/problem.php?id=1902

题目描述

【题目描述】 给出 N 滴水的坐标,y 表示水滴的高度,x 表示它下落到 x 轴的位置。
  每滴水以每秒 1 个单位长度的速度下落。
  你需要把花盆放在 x 轴上的某个位置,使得从被花盆接着的第 1 滴水开始,到被花盆接着的最后 1 滴水结束,之间的时间差至少为 D。
  我们认为,只要水滴落到 x 轴上,与花盆的边沿对齐或者在花盆中,就认为被接住。
  给出 N 滴水的坐标和 D 的大小,请算出最小的花盆的宽度 W。
在这里插入图片描述

【输入格式】 第1行:两个整数 N 和 D,1 <= N <= 100,000,1 <= D <= 1,000,000。
  接下来 N 行:每行两个整数 x,y,表示雨滴的坐标,0 <= x, y <= 1,000,000。
【输出格式】 仅一行 1 个整数,表示最小的花盆的宽度。
  如果无法构造出足够宽的花盆,使得在 D 单位的时间接住满足要求的水滴,则输出 −1。
【输入样例】

4 5
6 3
2 4
4 10
12 15

【输出样例】

2

题解

   题目的意思有点费解,用样例解释。有n = 4个水滴,把花盆放在某个地方接水滴,从接到第1个水滴开始,到接到最后一个水滴,要求落到花盆的所有水滴的总时间超过d = 6秒。问花盆的最小宽度是多少。答案是选第一个水滴(6, 3)和第三个水滴(4, 10),它们落到花盆里的时间差是10 - 3 = 7,超过6秒,花盆的宽度是6 - 4 = 2。
   下面概况题意。任选一个区间(花盆宽度)[L,R],统计这个区间内最大值和最小值(最高和最低水滴)的差,如果≥d,称为一个合法区间,记录区间宽度。遍历所有这种合法区间,找到最小宽度,就是答案。
   区间问题可以用尺取法,用快慢指针形成的“滑动窗口”遍历所有区间,计算复杂度 O ( n 2 ) O(n^2) O(n2),超时。本题至少需要 O ( n l o g n ) O(nlogn) O(nlogn)复杂度的算法。
   用滑动窗口遍历区间的方法,除了尺取法,还有单调队列。《算法竞赛》第10页有一道类似的例题“洛谷P1886”。给定一个固定的窗口宽度k,要求输出所有窗口宽度等于k的区间内的最大最小值。用单调队列求解,复杂度仅为 O ( n ) O(n) O(n)请仔细阅读这一节的内容,理解为什么复杂度是 O ( n ) O(n) O(n)
   本题和洛谷P1886相同的地方都是求窗口内最大最小值,区别是本题没有给定固定的窗口宽度。那么用二分法来猜一个最小的k即可:每次猜一个窗口宽度k,用函数check(k)判断窗口宽度为k时有没有合法的区间,函数check()用单调队列求解。“二分法+单调队列”的计算复杂度,二分法猜 O ( l o g n ) O(logn) O(logn)次,每次用check()求所有宽度为k的区间的最大最小值是 O ( n ) O(n) O(n)的,总复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
   代码中的单调队列是手写的(手写队列见《算法竞赛》,清华大学出版社,罗勇军、郭卫斌著,7页)。h是队头,t是队尾;保持h≤t,队列长度等于t - h + 1;h++表示弹出(删除)队头,t–表示弹走(删除)队尾。
   函数check(k)的功能是检查有没有一个宽度为k的合法窗口,这个窗口内的最大最小值差≥d。用两个单调队列分别求窗口内的最大和最小值。q1是单调递增队列,队头是最小值;q2是单调递减队列,队头是最大值。
【重点】 单调队列 。

C++代码

#include<bits/stdc++.h>
using namespace std;
const int N=100001;
int n,d;
int q1[N],q2[N];                  //q1队头是窗口内最小值,q2队头是窗口内最大值
struct node{int x,y;}a[N];
int cmp(node u,node v){ return u.x<v.x;}
bool check(int k){
    memset(q1,0,sizeof(q1));      //单调递增,队头最小
    memset(q2,0,sizeof(q2));      //单调递减,队头最大
    int h1=1,t1=0,h2=1,t2=0;      //h:队头,t队尾 ,注意保持 h<=t
    for(int i=1;i<=n;i++){        //a[i]一个个地进入队尾
        while(h1<=t1 && a[q1[h1]].x < a[i].x-k)  h1++;  //窗口宽度大于k了,弹走队头,减小到k
        while(h1<=t1 && a[i].y < a[q1[t1]].y)
            t1--;           //如果原队尾更大,删除队尾,保持队头a[q1[h1]].y最大
        q1[++t1]=i;         //现在队内都比a[i]小了,a[i]从队尾进队
        //前面几行求窗口内的最小值,下面几行求窗口内的最大值
        while(h2<=t2 && a[q2[h2]].x < a[i].x-k)  h2++;  //窗口宽度大于k了,弹走队头,减小到k
        while(h2<=t2 && a[i].y > a[q2[t2]].y)
            t2--;           //如果原队尾更小,删除队尾,保持队头a[q2[h2]].y最大
        q2[++t2]=i;         //现在队内都比a[i]大了,a[i]从队尾进队

        if(a[q2[h2]].y-a[q1[h1]].y >= d) return true; //最大最小之差大于等于d
    }
    return false;
}
int main(){
    cin>>n>>d;
    for(int i=1;i<=n;i++)  scanf("%d%d",&a[i].x,&a[i].y);
    sort(a+1,a+n+1,cmp);     // 根据x值升序
    int L=1,R=1e6,ans=-1;
    while(L<=R){             //二分求最小宽度
        int mid=(L+R)>>1;
        if(check(mid)) ans=mid,R=mid-1;
        else  L=mid+1;
    }
    cout<<ans<<endl;
    return 0;
}

Java代码

import java.util.*;
import java.io.*;
class Main {
    static class Node {
        int x, y; 
        Node(int x, int y) {
            this.x = x;
            this.y = y;
        }
    } 
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int d = scanner.nextInt();
        Node[] a = new Node[n + 1];
        for (int i = 1; i <= n; i++) {
            int x = scanner.nextInt();
            int y = scanner.nextInt();
            a[i] = new Node(x, y);
        }
        Arrays.sort(a, 1, n + 1, (u, v) -> u.x - v.x);
        int L = 1, R = 1000000, ans = -1;
        while (L <= R) {
            int mid = (L + R) >> 1;
            if (check(a, n, d, mid)) {
                ans = mid;
                R = mid - 1;
            } else {
                L = mid + 1;
            }
        }
        System.out.println(ans);
    }
 
    static boolean check(Node[] a, int n, int d, int k) {
        int[] q1 = new int[n+10];
        int[] q2 = new int[n+10];
        int h1 = 1, t1 = 0, h2 = 1, t2 = 0;
        for (int i = 1; i <= n; i++) {
            while (h1 <= t1 && a[q1[h1]].x < a[i].x - k) 
                h1++;
            while (h1 <= t1 && a[i].y < a[q1[t1]].y) 
                t1--;
            q1[++t1] = i; 
            while (h2 <= t2 && a[q2[h2]].x < a[i].x - k) 
                h2++;
            while (h2 <= t2 && a[i].y > a[q2[t2]].y) 
                t2--;
            q2[++t2] = i; 
            if (a[q2[h2]].y - a[q1[h1]].y >= d) 
                return true;
        }
        return false;
    }
}

Python代码

 #pypy
 import sys
input = sys.stdin.readline
def check(a, n, d, k):
    q1 = [0] * (n + 1)
    q2 = [0] * (n + 1)
    h1, t1, h2, t2 = 1, 0, 1, 0
    for i in range(1, n + 1):
        while h1 <= t1 and a[q1[h1]][0] < a[i][0] - k:    h1 += 1
        while h1 <= t1 and a[i][1] < a[q1[t1]][1]:        t1 -= 1
        t1 += 1
        q1[t1] = i
 
        while h2 <= t2 and a[q2[h2]][0] < a[i][0] - k:    h2 += 1
        while h2 <= t2 and a[i][1] > a[q2[t2]][1]:        t2 -= 1
        t2 += 1
        q2[t2] = i
 
        if a[q2[h2]][1] - a[q1[h1]][1] >= d:   return True
    return False
  
n, d = map(int, input().split())
a = [(0,0)]
for _ in range(n):
    x, y = map(int, input().split())
    a.append((x, y))
a.sort()
L, R, ans = 1, 1000000, -1
while L <= R:
    mid = (L + R) >> 1
    if check(a, n, d, mid):
        ans = mid
        R = mid - 1
    else:  L = mid + 1
print(ans)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/948093.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

得帆信息东区总经理周俊君:该采用低代码和无代码给繁重的SAP减减负了

数字化转型对任何有竞争力的业务都至关重要&#xff0c;组织踏上数字化转型之旅&#xff0c;意味着要么重新开始&#xff0c;要么在现有IT建设的基础上再接再厉。这段旅程不仅仅是采用新技术&#xff0c;而是寻求在高可用性的同时为客户提供差异化价值。为了帮助客户达成这些目…

报表技术POI和EasyPOI处理百万数据、CSV、Word

1、了解百万数据的导入 1.1 需求分析 使用POI基于事件模式解析案例提供的Excel文件 1.2 思路分析 用户模式&#xff1a; 加载并读取Excel时&#xff0c;是通过一次性的将所有数据加载到内存中再去解析每个单元格内容。当Excel数据量较大时&#xff0c;由于不同的运行环境可…

欧盟GMP附录-对气流流型的11条要求及解读

欧盟GMP附录《无菌药品生产》已经生效&#xff0c;本文总结了该附录对气流流型的11条要求&#xff0c;并进行延伸解读。 【气流流型检测仪】 具体11条如下&#xff0c;来自EU GMP 无菌附录。 1.洁净室和区域内的气流模式应可视化&#xff0c;以证明气流不会从低洁净级别区域进…

【数据结构】带头双向循环链表及其实现

目录 1.带头双向循环链表 2.带头双向循环链表实现 2.1初始化 2.2销毁 2.3头插 2.4链表打印 2.5头删数据 2.6尾插数据 2.7尾删数据 2.8链表判空 2.9查找一个数据 2.10在pos位置前插入数据 2.11删除pos位置 2.12求链表的长度 2.顺序表和链表的比较 1.带头双向循环…

字节前端实习的两道算法题,看看强度如何

最长严格递增子序列 题目描述 给你一个整数数组nums&#xff0c;找到其中最长严格递增子序列的长度。 子序列是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1,6,2,2,7…

使用DataX对MySQL 8.1进行数据迁移

1. 环境准备 1.1 下载DataX 这里采用直接下载的方式&#xff1a;https://datax-opensource.oss-cn-hangzhou.aliyuncs.com/202308/datax.tar.gz&#xff0c;不过这个包是真的有点大。 1.2 安装Python Python下载地址&#xff1a;https://www.python.org/downloads/ 安装的时…

【深度思考】如何优雅的实现脱敏?

最近做了个脱敏的需求&#xff0c;要对系统中的敏感信息&#xff0c;如手机号、车牌号、身份证号、银行卡号等进行脱敏显示。 效果类似下面这样&#xff1a; 简单来说&#xff0c;就是对敏感信息中的某几位进行掩码显示&#xff0c;常见的一般是使用*。 本篇文章就来讲解下在…

解析肖特基二极管NRVBS360BNT3G整流器的优缺点及应用

何为肖特基二极管整流器&#xff1f; 是一种常用的电子器件&#xff0c;用于将交流信号转换为直流信号。它由一个PN结和一个金属接触组成&#xff0c;具有较低的正向压降和快速的开关特性。 在正向偏置下&#xff0c;肖特基二极管具有较低的正向压降&#xff0c;通常为0.3-0.…

如何防范恶意邮件?只要做到这几点

目前&#xff0c;网络钓鱼仍然是企业面临的最大威胁之一&#xff0c;而恶意电子邮件只是网络攻击的起点。一旦进入&#xff0c;威胁行动者就可以展开下一阶段的攻击&#xff0c;例如勒索软件或数据窃取。而这将给被攻击的企业造成巨大的声誉和经济损失&#xff0c;甚至涉及法律…

node升级带来的问题及解决方案(digital envelope routines::unsupported)

由于项目需要将 node版本从16升级到了18&#xff0c;但是原有的老项目还是使用的16的环境&#xff0c;导致在运行老版本的时候出现错误 错误信息如下 Error: error:0308010C:digital envelope routines::unsupportedat new Hash (node:internal/crypto/hash:71:19)at Object.…

文件恢复工具推荐,这4款高效恢复数据!

“有什么好用的文件恢复工具推荐吗&#xff1f;我经常莫名其妙丢失文件&#xff01;而且还是一些很重要的文文件&#xff0c;我都不知道该怎么办了&#xff01;请大家帮帮我&#xff0c;感谢大家&#xff01;” 文件恢复对各位电脑用户来说可能都并不陌生。在使用电脑时&#x…

win | wireshark | 在win上跑lua脚本 解析数据包

前提说明&#xff1a;之前是在linux 系统上配置的&#xff0c;然后现在 在配置lua 脚本 &#xff0c;然后 分析指定协议 的 数据包 其实流程也比较简单&#xff0c;但 逻辑需要缕清来 首先要把你 预先准备的 xxx.lua 文件放到wireshark 的安装文件中&#xff0c;&#xff08;我…

easyexcel poi根据模板导出Excel

1.导入依赖 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.0.1</version> </dependency>2.代码实现 package com.jiayou.peis.manage.biz.cotroller;import com.alibaba.excel.…

vue2中使用全屏screenfull插件遇到的问题

1、安装screenfull6.0.2后&#xff0c;启动项目。报错 解决方案&#xff1a; 第一种&#xff1a;卸载6.0的版本&#xff0c;安装 screenfull5.1.0 第二种&#xff1a; vue.config.js文件中配置属性 第三种&#xff1a; 安装插件babel/plugin-proposal-nullish-coalescing-o…

c语言练习题40:深入理解字符串常量

深入理解字符串常量 #include<stdio.h> int main() {char str1[] "abcd";char* str2 "abcd";printf("%s\n", str1);printf("%s\n", str2);return 0; } char str1[] "abcd";是用字符串初始化数组。 char* str2 &…

AMBEO 双声道空间音频现已迈进直播制作领域

图片来源&#xff1a;Unsplash&#xff0c;作者&#xff1a;Bence Balla-Schottner AMBEO 双声道空间音频现已迈进直播制作领域 为所有观众解锁更加身临其境的听觉体验 森海塞尔将功能强大的 AMBEO 双声道空间音频技术引入了广播电视直播应用领域&#xff0c;对所有体育赛事广…

ssm实验室开放管理系统源码和论文

ssm实验室开放管理系统源码和论文096 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归…

海外ASO优化之如何分析我们的应用

分析我们的应用在商店中的可见度的当前状况&#xff0c;我们当前使用的关键词是否带来了任何转化&#xff1f;我们在每个关键词查询的搜索结果中排名如何&#xff1f;我们的类别排名如何&#xff1f; 1、将相关的添加到我们的跟踪列表中。 观察每个项目的变化和排名。接下来转…

拧紧燃气“安全阀”!汉威科技为城市生命线构筑安全监控网

防患于未“燃”&#xff0c;拧紧燃气“安全阀”&#xff0c;这是关乎亿万国人生命财产安全的大事&#xff0c;也一直是党和国家重点发力的民生工程。8月11日&#xff0c;国务院安委会正式印发《全国城镇燃气安全专项整治工作方案》&#xff0c;也让液化石油气全链条的安全问题成…