ACM寒假集训第二次专题任务

news/2025/3/11 15:42:04/文章来源:https://www.cnblogs.com/cytlllll/p/18692267

ACM寒假集训第二次专题任务

一、二分查找

题目:

联想截图_20250126163253

解题思路:

输入数据后把每一个x单独拎出来,通过二分查找检验是否存在于被测数组中。

AC代码:

#include<iostream>
using namespace std;
int main()
{int n,a[100000]={0},q,x[100000];cin>>n;for(int i=0;i<n;i++){cin>>a[i];}cin>>q;for(int i=0;i<q;i++){cin>>x[i];}for(int i=0;i<q;i++){int l=0,r=n-1,f=0;while(l<=r){int mid=(l+r)/2;if(a[mid]==x[i]){cout<<"Yes"<<endl;f=1;break;}else if(a[mid]<x[i]){l=mid+1;}else if(a[mid]>x[i]){r=mid-1;}}if(f==0){cout<<"No"<<endl;}}return 0;
}

二、A-B 数对

题目:

联想截图_20250126165320

解题思路:

  1. 分析题目:一个数对包含A,B,C三个数字,其中C为输入数据(可看作已知),同时分析A与B比较困难,对A-B=C进行改写,得A=C+B;

  2. 因为A、B都存在于输入的数组中,所以B也可以看作已知。此时只需要分析输入数组中A是否存在。

  3. 对输入数组从小到大进行排序,再通过二分查找进行搜索。

注:需要注意数值取值范围。

AC代码:

#include<iostream>
#include<algorithm>
using namespace std;
int lower(int l,int r,int target,int* num)
{int ans=0;while(l<=r){int mid=(l+r)/2;if(num[mid]==target){ans=mid;r=mid-1;}else if(num[mid]<target){l=mid+1;}else if(num[mid]>target){r=mid-1;}}return ans;
}
int upper(int l,int r,int target,int* num)
{int ans=0;while(l<=r){int mid=(l+r)/2;if(num[mid]==target){ans=mid;l=mid+1;}else if(num[mid]<target){l=mid+1;}else if(num[mid]>target){r=mid-1;}}return ans;
}
int main()
{int N,C,num[200000]={0};cin>>N>>C;for(int i=0;i<N;i++){cin>>num[i];}sort(num,num+N);long long sum=0;for(int i=0;i<N;i++){int A=num[i]+C;int ans=0;int l=lower(0,N,A,num);int r=upper(0,N,A,num);if(l==r){if(l==0){ans=0;}elseans=1;}elseans=r-l+1;sum+=ans;}cout<<sum<<endl;return 0;
}

三、分巧克力

题目:

联想截图_20250126165604

解题思路:

  1. 分析题目:求最大边长,可通过二分查找确定所求边长。

  2. 先明确左右端点,边长最小为1,故l=1;边长最大为100000,故r=100000。

  3. 再明确如何检验mid是否合理:(矩形的长/mid)*(矩形的宽/mid)即为该矩形所能切割的最大个数,与K比较,比K大说明mid还可以增大,比K小说明mid应该减小。

AC代码:

#include<iostream>
using namespace std;
struct square{int H;int W;
};
bool check(int mid,int N,int K,square a[])
{int cut=0;for(int i=0;i<N;i++){cut+=(a[i].H/mid)*(a[i].W/mid);}if(cut>=K){return 1;}else{return 0;}
}
int main()
{int N,K;cin>>N>>K;square a[100000];for(int i=0;i<N;i++){cin>>a[i].H>>a[i].W;}int l=1,r=1e5,ans=1;while(l<=r){int mid=(r+l)/2;if(check(mid,N,K,a)){l=mid+1;ans=mid;}else{r=mid-1;}}cout<<ans;return 0;
}

四、卡牌

题目:

联想截图_20250126165741

联想截图_20250126165821

解题思路:

本题使用二分答案。

  1. 明确查找对象:凑出的牌的套数;

  2. 确定check逻辑:限制可分成两个,一个是凑出mid套牌所需补充的牌数不得超过m;另一个是mid套牌不能大于某一牌现有牌数和对应限制补充牌数的最大值(max(a[i]+b[i]));

  3. 通过对两个check的分析对端点进行左右移动。

AC代码:

#include<iostream>
#include<vector>
using namespace std;
struct card{long long a;long long b;
};
long long smaller(long long a,long long b)
{if(a<b)return a;elsereturn b;
}
long long max(long long big[],long long n)
{int ma=big[0];for(int i=0;i<n;i++){if(big[i]>ma)ma=big[i];}return ma;
}
bool check(long long mid,long long n,long long m,vector<card>& c)
{long long need=0;for(long long i=0;i<n;i++){long long add=smaller(mid-c[i].a,c[i].b);if(add<=0){continue;}else{need+=add;}}return need<=m;
}
bool check2(long long mid,long long n,long long big[])
{for(long long i=0;i<n;i++){if(mid>big[i]){return 0;}}return 1;
}
int main()
{long long n,m;cin>>n>>m;long long big[n];vector<card> c(n);for(long long i=0;i<n;i++){cin>>c[i].a;}for(long long i=0;i<n;i++){cin>>c[i].b;big[i]=c[i].a+c[i].b;}long long l=0,r=max(big,n),ans=0;while(l<=r){long long mid=(r+l)/2;if(check(mid,n,m,c)&&check2(mid,n,big)){l=mid+1;ans=mid;}else{r=mid-1;}}cout<<ans;return 0;
}

五、书的复制

题目:

联想截图_20250126170817

联想截图_20250126170838

解题思路:

  1. 输入处理:读取书的数量 m、人的数量 k 以及每本书的页数。
  2. 二分查找最短复制时间:确定二分查找的左右边界,不断调整中间值,通过检查函数判断该时间是否满足要求,逐步缩小查找范围,直到找到最短复制时间。
  3. 书籍分配:根据最短复制时间,从后往前分配书籍,使得前面的人抄写的书尽可能少。
  4. 输出结果:输出每个人抄写的书的起始编号和终止编号。

AC代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int K = 500;
int m, k, a[K + 5];
int st[K + 5], ed[K + 5];inline int read() {int x = 0;bool f = 1;char ch = getchar();for (; ch < '0' || ch > '9'; ch = getchar()) f ^= (ch == '-');for (; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);return f ? x : -x;
}bool check(int limit) {int people = 1;int remainingPages = limit;for (int i = 1; i <= m; ++i) {if (a[i] > remainingPages) {people++;remainingPages = limit;}remainingPages -= a[i];}return people <= k;
}void solve() {m = read(), k = read();int left = 0, right = 0;for (int i = 1; i <= m; ++i) {a[i] = read();left = max(left, a[i]);right += a[i];}while (left < right) {int mid = left + (right - left) / 2;if (check(mid)) {right = mid;} else {left = mid + 1;}}ed[k] = m, st[1] = 1;int currentLimit = left;for (int i = k, j = m; i; --i) {while (currentLimit >= a[j] && j) {currentLimit -= a[j];j--;}st[i] = j + 1;ed[i - 1] = j;currentLimit = left;}for (int i = 1; i <= k; ++i) {cout << st[i] << ' ' << ed[i] << '\n';}
}signed main() {solve();return 0;
}

六、青蛙过河

题目:

联想截图_20250126191822

联想截图_20250126191838

解题思路:

  1. 输入处理:读取数组的长度 n、目标值 x 以及数组元素 H,同时对输入的 n 进行有效性检查。
  2. 构建前缀和数组:通过遍历数组 H,计算并存储前缀和到数组 sum 中,以便后续快速计算任意子数组的和。
  3. 二分查找最小长度:在可能的长度范围 [1, n] 内进行二分查找,对于每个中间长度 mid,使用 check 函数检查是否所有长度为 mid 的子数组的和都满足条件。
  4. 输出结果:二分查找结束后,输出满足条件的最小长度。

AC代码:

#include <iostream>
#include <cstdio>
using namespace std;const int N = 1e5;
int n, x, H[N + 5], sum[N + 5];inline int read() {int x = 0;bool f = 1;char ch = getchar();for (; ch < '0' || ch > '9'; ch = getchar())f ^= (ch == '-');for (; ch >= '0' && ch <= '9'; ch = getchar())x = (x << 1) + (x << 3) + (ch ^ 48);return f? x : -x;
}bool check(int mid) {for (int i = 1; i + mid - 1 < n; ++i) {int L = i, R = i + mid - 1;if (sum[R] - sum[L - 1] < 2 * x) return 0;}return 1;
}void Kafka() {n = read();if (n < 1 || n > N) {cerr << "Invalid value of n" << endl;return;}x = read();for (int i = 1; i < n; ++i) {H[i] = read();}for (int i = 1; i < n; ++i) sum[i] = H[i] + sum[i - 1];int L = 1, R = n;while (L < R) {int mid = L + (R - L) / 2;if (check(mid)) {R = mid;} else {L = mid + 1;}}cout << L << '\n';
}int main() {Kafka();return 0;
}

学习总结

二分查找

二分查找适用于有序数据、具有单调性的查找目标以及数据规模较大的场景,能够显著提高查找效率。

思路简单,上手快,可套模板。但需搞清端点取值及加不加等号的问题。

二分答案

以二分查找为基础,明确需要查找的答案(例如,以上题目中正方形边长)是什么,并且设计如何检验mid合理性(难点所在)。

还是得多做。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于慧净电子HJ-5G开发板学习记录(1)——PIC16F877A开发流水灯

(1)流水灯介绍 下图为慧净电子HJ-5G开发板流水灯部分的电路,其中需要先将JP1跳线帽接上进行短接操作,这样8个流水灯呈现共地状态。此时如果想要实现流水灯操作,只需要轮流将A、B、C、D、E、F、G、H这8个引脚的1个赋值为高电平,其余引脚赋值为低电平即可。而其中,如下图所…

基于慧净电子HJ-5G开发板学习记录——PIC16F877A开发流水灯

(1)流水灯介绍 下图为慧净电子HJ-5G开发板流水灯部分的电路,其中需要先将JP1跳线帽接上进行短接操作,这样8个流水灯呈现共地状态。此时如果想要实现流水灯操作,只需要轮流将A、B、C、D、E、F、G、H这8个引脚的1个赋值为高电平,其余引脚赋值为低电平即可。而其中,如下图所…

深入理解Mybatis分库分表执行原理

探究分库分表场景下Mybatis是如何将mapper.xml中sql的逻辑表,转换成实际执行时的物理表。前言 工作多年,分库分表的场景也见到不少了,但是我仍然对其原理一知半解。趁着放假前时间比较富裕,我想要解答三个问题:为什么mybatis的mapper.xml文件里的sql不需要拼接表名中的分表…

dell r730xd安装操作系统时遇到的常见问题。

出现这个问题时,需要明确你的系统是已经安装完成并且没有问题的,那么就开机时按F11进入选择引导程序,然后选择指定硬盘的系统进行启动接口。 其他待补充。。。。复制请注明出处,在世界中挣扎的灰太狼

三. Redis 基本指令(Redis 快速入门-03)

三. Redis 基本指令(Redis 快速入门-03) @目录三. Redis 基本指令(Redis 快速入门-03)1. Redis 基础操作:2. 对 key(键)操作:3. 对 DB(数据库)操作4. 最后: Reids 指定大全(指令文档): https://www.redis.net.cn/order/Redis 命令十分丰富,包括的命令组有 Cluster、Conne…

在Lazarus下的Free Pascal编程教程——应用程序配置数据的管理与使用

0.前言 我想通过编写一个完整的游戏程序方式引导读者体验程序设计的全过程。我将采用多种方式编写具有相同效果的应用程序,并通过不同方式形成的代码和实现方法的对比来理解程序开发更深层的知识。了解我编写教程的思路,请参阅体现我最初想法的那篇文章中的“1.编程计划”和“…

算法学习笔记:扫描线

前言 之前没什么理解,一做就废,最近集训讲了这个,感觉认识深刻了很多,遂写笔记。 这里讲的扫描线,更精确来说指的是离线二维数点,即用扫描线维护一维,DS 维护另一维。 概念 我们把二维数点放到平面上来,那么一个询问或限制就对应平面上的一个矩形,定义这个矩形的 \(\t…

干掉visio,这个画图神器真的绝了!!!

前言 看过我以往文章的小伙伴可能会发现,我的大部分文章都有很多配图。我的文章风格是图文相结合,更便于大家理解。 最近有很多小伙伴发私信问我:文章中的图是用什么工具画的。他们觉得我画的图风格挺小清新的,能够让人眼前一亮。 先上几张图让大家看看效果:说实话,问我的…

面试题|线程池里有几个线程在运行

本文主要改编自https://www.sohu.com/a/391767502_355142。下面从一道面试题引入本文主题~~ 面试官:"假设有一个线程池,核心线程数为10,最大线程数为20,任务队列长度为100。如果现在来了100个任务,那么线程池里有几个线程在运行?" 粉丝豪:"应该是10吧!&…