蓝桥杯之二分与前缀和

news2024/11/14 13:53:27

蓝桥杯之二分

    • 二分板子?第一次和最后一次出现的位置
    • 机器人跳跃问题
    • 四平方和
    • 分巧克力?典型二分找大的(从右往左找)
    • 二分upper_bound(a+1,a+n+1,x)-a?递增三元组
    • 前缀和取余?K倍区间
    • 二维前缀和?激光炸弹

二分板子?第一次和最后一次出现的位置

目的总是取到一个最合适的值。
首先,找到取值的范围,在该范围内进行二分。
判断取值是否满足题意条件
……

整数二分模板一共有两个,分别适用于不同情况。
算法思路:假设目标值在闭区间 [ l , r ] [l, r] [l,r]中, 每次将区间长度缩小一半,当 l = r l = r l=r时,我们就找到了目标值。

模板一:(再也不用为边界的处理而头痛了)
当我们将区间 [ l , r ] [l, r] [l,r]划分成 [ l , m i d ] [l, mid] [l,mid] [ m i d + 1 , r ] [mid + 1, r] [mid+1,r]时,其更新操作是 r = m i d r = mid r=mid或者 l = m i d + 1 l = mid + 1 l=mid+1;,计算 m i d mid mid时不需要加1。

int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    return l;
}

模板二:
当我们将区间 [ l , r ] [l, r] [l,r]划分成 [ l , m i d − 1 ] [l, mid - 1] [l,mid1] [ m i d , r ] [mid, r] [mid,r]时,其更新操作是 r = m i d − 1 r = mid - 1 r=mid1或者 l = m i d l = mid l=mid;,此时为了防止死循环,计算 m i d mid mid时需要加1。

边界的处理:
死循环的解释是:例如二分区间缩小到 l=3,r=4 时,l=mid ,mid的算法一定是向上取整,否则一直取的是3
或者解释为,要保持一致的区间分割方式

int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

这两种情况就是一个是从小到大找,一个是从大到小找。因为二分的前提是要有序(一般都是,搜索的范围中值是升序的,寻找满足条件的最小值,那么当adequate(mid),对应的就是 模板一 r=mid,
相反,如果要找满足条件的最大值,那么当adequate(mid),对应的就是 模板二 l=mid

浮点数二分

bool check(double x) {/* ... */} // 检查x是否满足某种性质

double bsearch_3(double l, double r)
{
    const double eps = 1e-6;   // eps 表示精度,取决于题目对精度的要求
    while (r - l > eps)
    {
        double mid = (l + r) / 2;
        if (check(mid)) r = mid;
        else l = mid;//不能是mid减1噢,这可是浮点数,1是精度的巨大倍 
    }
    return l;
}

在这里插入图片描述

#include <iostream>
#include <stdlib.h>
#include <algorithm>
using namespace std;
int n,q; 
const int N=1e5+5;
int a[N];
void search(int t){
	int l=0;int r=n-1;
	while(l<r){
		int mid=l+(r-l)/2;
		if(a[mid]<t){
			l=mid+1;
		}
		else r=mid;
	};
	if(a[l]!=t){
		cout<<"-1 -1";
		return ;
	}
	cout<<l<<" ";
	r=n-1;
	while(l<r){
		int mid=l+(r-l+1)/2;
		if(a[mid]<=t){
			l=mid;
		}
		else r=mid-1;
	}
	cout<<l;
}

int main(){
	cin>>n>>q;
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	sort(a,a+n);//题外话:第3个参数 greater<int>()
	int t;
	while(q--){
		cin>>t;
		search(t);
		if(q)cout<<endl;
	}
	return 0;
} 

机器人跳跃问题

根据题意可知,每过一个建筑,能量 E E E 会转变成 2 E − H [ i ] 2E-H[i] 2EH[i]
随初始能量 E E E 单调增长,可以对初始能量 E E E 进行二分

	if(x>=1e5)return true;

判断二分值是否合法时,要防止爆int变成负值,那么将永远不合法,永远返回二分的最右边的值
n最大可达1e5,按照x的计算方式(指数爆增),
2^(1e5)早就爆了longlong变成一个负值 ,于是返回二分的最右边的值

#include <iostream>
#include <stdlib.h>
#include <string.h>

using namespace std;
int n; 
const int N=1e5+5;
int a[N];
bool adequate(int x){
	for(int i=0;i<n;i++){
		x=x*2-a[i];
		if(x<0)return false;
		if(x>=1e5)return true;//n最大可达1e5,按照x的计算方式,
//		2^(1e5)早就爆了longlong变成一个负值 ,于是返回二分的最右边的值 
	}
	return true;
}
int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	int l=0,r=1e5;
	while(l<r){
		int mid=l+(r-l)/2;
		if(adequate(mid))r=mid;
		else l=mid+1;
	}
	cout<<l;
	return 0;
} 

四平方和

在这里插入图片描述
思路速递
数量级 1 e 6 1e6 1e6,复杂度应该为 n n n 或者 n l o g n nlogn nlogn
1、abcd皆小于 n \sqrt{n} n ,暴力枚举abc,时间复杂度为 n ∗ n ∗ n = n n \sqrt{n}*\sqrt{n}*\sqrt{n}=n\sqrt{n} n n n =nn ,不可行
2、先枚举cd所有可能的组合的和,存放在哈希表中,接下来枚举ab,在查找 n − ( a + b ) n-(a+b) n(a+b) 是否在哈希表中存在

存放 这一步非常有门道,首先 “输出第一个表示法”,只需保存字典序最小的 c d cd cd 组合, 故想用map容器存放,只需要map 而不需要 unordered_map
或者 直接将 c d cd cd 组合存放在数组中,直接 O ( 1 ) O(1) O(1) 查询,时间复杂度为 O ( n ) O(n) O(n)
或者将所有 c d cd cd 组合(和相同的也全部存下)存放在 vector 数组中,则需要根据 cd和排序,内部按字典序排序(cd和相同按cd字典序),再二分,时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn) 如此

存放在map容器中,超时

#include <iostream>
#include <stdlib.h>
#include <algorithm>
using namespace std;
int n; 
const int N=1e5+5;
int a[N];
#define PII pair<int,int> 
#include <map>
map<int,PII> mp;

int main(){
	cin>>n;
	for(int c=0;c*c<n;c++){
		for(int d=c;d*d<=n;d++){
			int t=c*c+d*d;
			if(mp.find(t)==mp.end()){
				mp.insert({t,{c,d}});
			}
		}
	}
		for(int a=0;a*a*4<=n;a++){
		for(int b=a;a*a+b*b<=n/2;b++){
			int t=n-a*a-b*b;
			if(mp.find(t)!=mp.end()){
				cout<<a<<" "<<b<<" "<<mp[t].first<<" "<<mp[t].second<<endl;
				return 0;
			}
		}
	}
	return 0;
} 

像只枚举ab,借助 n − a ∗ a − b ∗ b n-a*a-b*b naabb 搜索剩余两个一样
存放时,可以存放部分信息,剩下的部分通过条件计算得到

#include <iostream>
#include <stdlib.h>
#include <math.h>
#include <algorithm>
using namespace std;
int n; 
const int N=1e5+5;
int a[N];
#define PII pair<int,int> 
#include <map>
map<int,int> mp;

int main(){
	cin>>n;
	for(int c=0;c*c<n;c++){
		for(int d=c;d*d<=n;d++){
			int t=c*c+d*d;
			if(mp.find(t)==mp.end()){
				mp.insert({t,c});
			}
		}
	}
		for(int a=0;a*a*4<=n;a++){
		for(int b=a;a*a+b*b<=n/2;b++){
			int t=n-a*a-b*b;
			if(mp.find(t)!=mp.end()){
				cout<<a<<" "<<b<<" "<<mp[t]<<" "<<sqrt(t-mp[t]*mp[t])<<endl;
				return 0;
			}
		}
	}
	return 0;
} 

进而不需要利用map容器,直接存放在数组中(cd 组合的值、c值)

#include <iostream>
#include <stdlib.h>
#include <math.h>
#include <algorithm>
using namespace std;
int n; 
const int N=5e6+5;
int p[N];
#define PII pair<int,int> 
#include <map>
map<int,int> mp;

int main(){
	cin>>n;
	for(int c=0;c*c<n;c++){
		for(int d=c;d*d<=n;d++){
			int t=c*c+d*d;
			if(t>n)continue;//否则t值很大,数组越界 
			if(!p[t]){
				p[t]=c+1;//存放的值与0错开,0默认为之前未出现过,真正的0存的是1 
			}
		}
	}
		for(int a=0;a*a*4<=n;a++){
		for(int b=a;a*a+b*b<=n/2;b++){
			int t=n-a*a-b*b;
			if(p[t]){
				int c=p[t]-1;
				cout<<a<<" "<<b<<" "<<c<<" "<<sqrt(t-c*c)<<endl;
				return 0;
			}
		}
	}
	return 0;
} 

分巧克力?典型二分找大的(从右往左找)

#include <iostream>
#include <stdlib.h>
#include <math.h>
#include <algorithm>
using namespace std;
int n,k; 
const int N=1e5+5;
int h[N]; 
int w[N];
bool adequate(int x){
	int cnt=0;
	for(int i=0;i<n;i++){
		if(h[i]<x||w[i]<x)continue;
		cnt+=(h[i]/x)*(w[i]/x);
	}
	if(cnt>=k)return true;
	else return false;
}
int search(int l,int r){
	while(l<r){
		int mid=l+(r-l+1)/2;
		if(adequate(mid)){
			l=mid;
		}
		else r=mid-1;
	}
	return l;
}
int main(){//19
	cin>>n>>k;
	int l=1;
	int r=0;
	for(int i=0;i<n;i++){
		cin>>h[i]>>w[i];
		r=max(r,h[i]);
		r=max(r,w[i]);
	}
	cout<<search(l,r);
	return 0;
} 

二分upper_bound(a+1,a+n+1,x)-a?递增三元组

xy也要取longlong,否则xy相乘就会强制转换为int,导致错误

#include <iostream>
#include <stdlib.h>
#include <algorithm>
using namespace std;
#define ll long long int
int n; 
const int N=1e5+5;
int a[N];
int b[N];
int c[N];
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){
		cin>>b[i];
	}
	for(int i=1;i<=n;i++){
		cin>>c[i];
	}
	sort(a + 1, a + 1 + n);
    sort(b + 1, b + 1 + n);
    sort(c + 1, c + 1 + n);
    ll res=0;
	for(int i=1;i<=n;i++){
		ll x=(lower_bound(a+1,a+n+1,b[i])-a)-1;
		ll y=n-(upper_bound(c+1,c+n+1,b[i])-c)+1;
		res+=x*y;
	}
	cout<<res;
	return 0;
} 

前缀和取余?K倍区间

区间和等于k的倍数无非两中情况
一:区间 1 ~ i,这种只需要计算 求余前缀和为0的次数
二:区间 i ~ j,这种处于里段的区间段,在 两个相等的前缀和 之间
对前缀和取模之后,两个相等的前缀和就能组成一个k倍区间
注意,res 是区间个数,n的平方级别,会爆int

#include <iostream>
#include <stdlib.h>
#include <algorithm>
using namespace std;
#define ll long long int
int n,k; 
const int N=1e5+5;
int s[N];
int cnt[N];
signed main(){
	cin>>n>>k;
	ll res=0;
	int x;
	for(int i=1;i<=n;i++){
		cin>>x;
		s[i]=(s[i-1]+x)%k;
		res+=cnt[s[i]];//两个相同的前缀和 
		cnt[s[i]]++;
	}
	cout<<res+cnt[0];
	return 0;
} 

上来就一个TLE,真难过

#include <iostream>
#include <stdlib.h>
#include <algorithm>
using namespace std;
//#define ll long long int
int n,k; 
const int N=1e5+5;
int a[N];
int s[N];
signed main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		s[i]=s[i-1]+a[i];
	}
	int cnt=0;
	for(int i=1;i<=n;i++){
		for(int j=i;j<=n;j++){
			if((s[j]-a[i-1])%k==0)cnt++;
		}
	}
	cout<<cnt;
	return 0;
} 

二维前缀和?激光炸弹


1、不能开两个数组(直接在原数组上求二维前缀和就好),因为每个数组是5000x5000这么大,就是5000x5000x4bytes,5000x5000x4/1024/1024=95MB,这题的空间是168MB,所以两个数组会MLE。
一个数组就行了,在自己身上求前缀和。

2、 xy坐标是从0开始的。

边界问题:

	r=min(r,max(mx,my));

r是不能减小的,比如 4 5 3,
不能因为最后一个双重循环从r开始,r必须小于mx,my,就随意减小r
且 为了得到最佳res,极有可能出现r的范围 圈住了空地(即超出了5*3范围)
故而,只能选择将mx,my搞大,一定要都大于r,才能让r肆意圈地
这样一来,4 5 4
求前缀和时不能只求 行1~ 5,列1~ 3 的,否则 例如列1~4的前缀和就会误以为0,实际上等于3列所有

	r=min(r,5001);  ✔
	mx=max(mx,r);
	my=max(my,r); 

但 r 超过a数组的大小也没有意义

#include <iostream>
#include <stdlib.h>
#include <math.h>
#include <algorithm>
using namespace std;
//#define ll long long int
int n,r; 
const int N=5005;
int a[N][N];
//int sum[N][N];
signed main(){//30
	cin>>n>>r;
	int x,y,w;
	int mx=0,my=0;
	for(int i=1;i<=n;i++){
		cin>>x>>y>>w;
		a[x+1][y+1]+=w;
		mx=max(mx,x+1);
		my=max(my,y+1);
	}
	r=min(r,5001);
	mx=max(mx,r);
	my=max(my,r);
	int res=0;
	for(int i=1;i<=mx;i++){//二维矩阵前缀和 
		for(int j=1;j<=my;j++){
			a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
		}
	}
	for(int i=r;i<=mx;i++){//二维矩阵前缀和 
		for(int j=r;j<=my;j++){
			int tmp=a[i][j]-a[i-r][j]-a[i][j-r]+a[i-r][j-r];
			res=max(res,tmp); 
		}
	} 
	cout<<res;
	return 0;
} 
//边界问题,求边长为r正方形内总和,借助矩阵前缀和 
//	1 2 3 4 5
//	1 2 3 4 5
//	1 2 3 4 5

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

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

相关文章

17种编程语言实现排序算法-合并排序

开源地址 https://gitee.com/lblbc/simple-works/tree/master/sort/ 覆盖语言&#xff1a;C、C、C#、Java、Kotlin、Dart、Go、JavaScript(JS)、TypeScript(TS)、ArkTS、swift、PHP。 覆盖平台&#xff1a;安卓(Java、Kotlin)、iOS(SwiftUI)、Flutter(Dart)、Window桌面(C#)、…

分享139个ASP源码,总有一款适合您

ASP源码 分享139个ASP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 139个ASP源码下载链接&#xff1a;https://pan.baidu.com/s/1Vk4U4EXVCWZWPMWf9ax2dw?pwdif23 提取码&#x…

【C++】类和对象(上)---什么是类?

目录1.面向过程和面向对象初步认识2.类的引入2.1使用struct定义类3.类的定义3.1类的两种定义方式&#xff1a;3.2成员变量命名规则的建议3.3成员函数与成员变量定义的位置建议4.类的访问限定符及封装4.1访问限定符4.2封装5.类的作用域6.类的实例化7.类对象模型7.1如何计算类对象…

springboot静态资源目录访问,及自定义静态资源路径,index页面的访问

springboot静态资源目录访问&#xff0c;及自定义静态资源路径&#xff0c;index页面的访问静态资源目录的访问位置静态资源访问测试自定义静态资源路径和静态资源请求映射web首页的访问自定义静态资源请求映射影响index.html首页的访问的**解决方案**&#xff1a;1.取消自定义…

【JUC系列】CountDownLatch实现原理

简单示例 public class Main {private static final int NUM 3;public static void main(String[] args) throws InterruptedException {CountDownLatch latch new CountDownLatch(NUM);for (int i 0; i < NUM; i) {new Thread(() -> {try {Thread.sleep(2000);Syste…

梯度之上:Hessian 矩阵

原文链接&#xff1a;原文 文章目录梯度之上&#xff1a;Hessian 矩阵梯度、雅克比矩阵海森矩阵海森矩阵应用梯度之上&#xff1a;Hessian 矩阵 本文讨论研究梯度下降法的一个有力的数学工具&#xff1a;海森矩阵。在讨论海森矩阵之前&#xff0c;需要首先了解梯度和雅克比矩阵…

基础知识一览3

这里写目录标题1.Servlet1.1 入门1.2 什么是Servlet1.3 Servlet的作用1.4 Servlet生命周期1.5 Servler的体系结构1.6 Servler的两种配置方式2.Filter2.1 Filter拦截路径配置2.2 过滤器链2.2 入门2.3 过滤器链2.4 过滤器生命周期3.Listener3.1 监听器分类3.1.1 一类监听器4.Serv…

ESP32设备驱动-GA1A12S202光线传感器驱动

GA1A12S202光线传感器驱动 1、GA1A2S202介绍 GA1A1S202 对数刻度模拟光传感器使用起来非常简单,只需添加电源,然后监控模拟输出。大多数光传感器对光强度具有线性响应,这意味着它们对低光水平非常不敏感,然后在高光水平下达到最大值。另一方面,该传感器具有对数响应,这…

第九届蓝桥杯省赛 C++ B组 - 乘积最大

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4da;专栏地址&#xff1a;蓝桥杯题解集合 &#x1f4dd;原题地址&#xff1a;乘积最大 &#x1f4e3;专栏定位&#xff1a;为想参加蓝桥杯的小伙伴整理常考算法题解&#xff0c;祝大家…

Thread的join()方法的作用

文章目录官方文档对join()的解释&#xff1a;结合实例解释官方文档对join()的解释&#xff1a; Thread.join() method javadocs&#xff08;点击跳转&#xff09; join() Waits for this thread to die. 线程类的 join()方法将等待子线程完成&#xff0c;然后继续当前线程。j…

【Python】常见的时间操作(时间区间、时间相加减、指定年月天数等。。。

前言 记录在Python中使用的时间操作&#xff0c;方便以后查找。 在使用Python中&#xff0c;常会遇到关于时间的操作。 虽说每次都能借助搜索引擎找到解决的方法&#xff0c;但好记性不如烂笔头&#xff0c;遂有此文。 暂时记录了笔者所使用过的Python关于时间的操作&#xff0…

人世正道沧桑,她亦奋力向前 --读《李清照传》有感

有一次陪小孩晨读&#xff0c;朗诵诗歌&#xff0c;读到了李清照的《夏日绝句》&#xff1a;“生当作人杰&#xff0c;死亦为鬼雄。至今思项羽&#xff0c;不肯过江东”。这首诗是1129年&#xff0c;李清照在芜湖的乌江县触景生情&#xff0c;有感而作的。这首诗写得大气磅礴&a…

JQuery总结(一)

JQUERY概述&#xff1a; JQUERY和DOM相互转换&#xff1a; 基础选择器&#xff1a; 筛选选择器&#xff1a; show hide toggle方法 jQuery hover方法 jQuery stop()方法 例子&#xff1a;显示、隐藏、切换 button{/* 随着字体大小变化,button跟着变化大小 */font-size: 20px;ba…

【Git】国内代码托管中心码云(Gitee)

9、国内代码托管中心码云(Gitee) 9.1、简介 众所周知&#xff0c;GitHub 服务器在国外&#xff0c;使用 GitHub 作为项目托管网站&#xff0c;如果网速不好的话&#xff0c;严重影响使用体验&#xff0c;甚至会出现登录不上的情况。针对这个情况&#xff0c;大家也可以使用国…

边界框回归 Bounding-Box Regression

文章目录边界框回归&#xff08;Bounding-Box Regression&#xff09;一、边界框回归简介二、边界框回归细节三、相关问题思考1. 为什么使用相对坐标差?2. 为什么宽高比要取对数?3. 为什么IoU较大时边界框回归可视为线性变换&#xff1f;边界框回归&#xff08;Bounding-Box …

协调中心性能大对比:zookeeper是如何解决负载均衡问题的

作为分布式系统的一个长久话题&#xff0c;协调中心的性能是一个很有意思的突破口。 作为java的分布式协调中心&#xff0c;常见的有zookeeper&#xff0c;redis &#xff0c;memcache等全局性功能的组件&#xff0c;也有MySQL&#xff0c;mongoDB之类的数据库形持久存储。 两…

PyCharm无法打开,提示Internal error错误。

安装LeetCode插件后&#xff0c;重新打开PyCharm后&#xff0c;出现该错误。 删除安装目录下的 plugins 文件夹后&#xff0c;重新打开后&#xff0c;又出现该错误。 重新把回收站的文件夹恢复后&#xff0c;再次打开还是之前那个错误。 尝试了 cmd ,powershell&#xff0c;管…

Python Flask构建微信小程序订餐系统 (五)

🔥 微信小程序登录态 🔥 所谓登录态,就是程序在运行时,能够识别当前用户,能够证明自己的唯一性且合法。 WEB服务器通过浏览器携带的cookie获取session来判断是否是同一用户(或浏览器);Restful服务通过客户端传过来唯一ID,来识别调用用户。 维护登录态的原因 有自身…

行为型模式-模板方法模式

1.概述 在面向对象程序设计过程中&#xff0c;程序员常常会遇到这种情况&#xff1a;设计一个系统时知道了算法所需的关键步骤&#xff0c;而且确定了这些步骤的执行顺序&#xff0c;但某些步骤的具体实现还未知&#xff0c;或者说某些步骤的实现与具体的环境相关。 例如&…

机器学习(五):机器学习算法分类

文章目录 机器学习算法分类 一、监督学习 1、回归问题 2、分类问题 二、无监督学习 三、半监督学习 四、强化学习 机器学习算法分类 根据数据集组成不同&#xff0c;可以把机器学习算法分为&#xff1a; 监督学习无监督学习半监督学习强化学习一、监督学习 定义&…