蓝桥杯训练day2
day2
- 1.二分
- (1)789. 数的范围
- (2)四平方和
- (1)哈希表做法
- (2)二分做法
- (3)1227. 分巧克力
- (4)113. 特殊排序
- (5)1460. 我在哪?
- 2.双指针
- (1)1238. 日志统计
- (2)1240. 完全二叉树的权值
- (3)字符串删减
- (4)799. 最长连续不重复子序列
- (5)800. 数组元素的目标和
- (6)判断子序列
1.二分
(1)789. 数的范围

思路:
需要找到一个值的区间。比如1 2 2 3 4 5 找2的区间,即[1,2]
因为数组是有序的,所以可以使用二分查找。
(1)使用二分查找找左边界
(2)使用二分查找找右边界
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;const int N=100010;int n,q;int a[N];int find1(int t) //找到当前查找数的区间左边界
{int res=-1;int l=0,r=n-1;int mid=(l+r)>>1;while(l<=r){mid=(l+r)>>1;if(a[mid]>t)r=mid-1;else if(a[mid]<t)l=mid+1;else{res=mid;r=mid-1;}}return res;
}int find2(int t)
{int res=-1;int l=0,r=n-1;int mid=(l+r)>>1;while(l<=r){mid=(l+r)>>1;if(a[mid]>t)r=mid-1;else if(a[mid]<t)l=mid+1;else{res=mid;l=mid+1;}}return res;
}int main()
{cin>>n>>q;for(int i=0;i<n;i++)cin>>a[i];while(q--){int t;cin>>t;cout<<find1(t)<<" "<<find2(t)<<endl;}return 0;
}
(2)四平方和

经典哈希问题,二分问题。
第一步:先找出两个数的平方和的所有组合(不超过n)
第二步:n减去两个数的平方和,剩下的数看是否在第一步预处理过。
为什么可以保证字典序最小呢:
(1)在第二步中,a,b是从小到大枚举的,且可以保证a<=b恒成立,为什么?如果a>b成立,那么把a,b置换一下,一样成立。然后第一次成立就会结束,所以不可能遇到a>b的情况
(2)C[k],D[k]也是一样的道理。在第一步就可以证明。
(1)哈希表做法
#include<iostream>
#include<cstring>
using namespace std;const int N=5000010;int C[N],D[N];int n;int main()
{cin>>n;memset(C,-1,sizeof C);//第一步:将所有两个数的组合都算出来for(int a=0;a*a<=n;a++){for(int b=a;b*b+a*a<=n;b++){int k=a*a+b*b;if(C[k]==-1){C[k]=a,D[k]=b;}}}//第二步,将n减去ab两个数的组合,剩下的看之前是否存储,如果有,直接输出。而且一定满足字典序最小for(int a=0;a*a<=n;a++){for(int b=a;b*b+a*a<=n;b++){int k=n-a*a-b*b;if(C[k]!=-1){cout<<a<<" "<<b<<" "<<C[k]<<" "<<D[k]<<endl;return 0;}}}return 0;}
(2)二分做法
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;const int N=5000010;struct Sum
{int s,c,d; //s表示a*a+b*bbool operator<(const Sum &t)const //为什么重载小于号{if(s!=t.s)return s<t.s;if(c!=t.c)return c<t.c;return d<t.d;}
}sum[N];int n;
int m;int main()
{cin>>n;for(int c=0;c*c<=n;c++)for(int d=c;c*c+d*d<=n;d++)sum[m++]={c*c+d*d,c,d};sort(sum,sum+m);for(int a=0;a*a<=n;a++){for(int b=a;b*b+a*a<=n;b++){int t=n-a*a-b*b;int l=0,r=m-1;while(l<r){int mid=(l+r)>>1;if(t<=sum[mid].s)r=mid;elsel=mid+1;}if(t==sum[l].s) //或者t==sum[r].s 因为最终l==r{cout<<a<<" "<<b<<" "<<sum[r].c<<" "<<sum[r].d<<endl;return 0;}}}return 0;
}
(3)1227. 分巧克力

还以为有什么技巧咧,看半天。。就一个暴力做法。。。二分正方形的边长
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;const int N=1e5+10;int n,k;int H[N],W[N];bool check(int t)
{long long res=0;for(int i=0;i<n;i++){res+=H[i]/t*(W[i]/t);if(res>=k)return true;}return false;
}
int main()
{cin>>n>>k;for(int i=0;i<n;i++)cin>>H[i]>>W[i];int l=1,r=1e5;while(l<r){int mid=(l+r+1)>>1; //为什么+1,这是因为避免死循环,为什么会死循环。博客里面有相关文章if(check(mid))l=mid;elser=mid-1;}cout<<l<<endl;return 0;
}
(4)113. 特殊排序

难难难!!!
关键在于对“无序二分”的合理证明。
二分一定是有道理才能的。光看难懂,要仔细体会。不会的小伙伴可以私信,我这个菜鸟看了30分钟才看懂😢
// Forward declaration of compare API.
// bool compare(int a, int b);
// return bool means whether a is less than b.class Solution
{
public:vector<int> specialSort(int N) {vector<int>res;res.push_back(1); //使用插入排序+二分,res就是排序主体,开始数组只有1个元素,当然是有序的for(int i=2;i<=N;i++){//这里规定找到第一个小于i的位置,且该位置后面一个数大于i。然后让i插入到第一个小于i的位置后面的一个位置//这是合理的.//如果当前数x比i小,那么i一定可以在x右边放下:如果x右边所有的数都比i小,那么i放在最右端//如果x右边有一个数比i大,那么i放在该数位置,该数以及后面的数右移。//所以找到第一个小于i的数且后面大于i的数(也可以没有)即可//注意,如果没有小于i的数,那么i放在第一位int l=0,r=res.size()-1;while(l<r){int mid=(l+r+1)>>1;if(compare(res[mid],i))l=mid; //如果mid小于i,那么i一定可以插入到mid后面(也可能可以插入到mid左边)elser=mid-1;}res.push_back(i);//最后l==r,[l,l+1]分别表示小于i,大于i的数for(int j=res.size()-2;j>r;j--)swap(res[j],res[j+1]);//判断r是否合理。如果i比res[r]小,则和我们假设不符合,那么就只有一种可能,i比所有数都小,自然也比第一个数小,这个时候i只可能是第二个数,那么和第一个数交换位置即可if(compare(i,res[r]))swap(res[r],res[r+1]);//也可写 if(compare(res[r+1],res[r])swap(res[r],res[r+1]);}return res;}
};
(5)1460. 我在哪?

这道题数据很小,可以直接暴力解决。直接枚举所有连续的字符串的组合,找到唯一的那一个,记录下长度即可,非常简单。但是标签是二分,待我去看看题解如何解答。。
//目的找到一个最小长度且没有重复的字符串#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;const int N=110;int n;
char str[N];
int res;int main()
{cin>>n;for(int i=1;i<=n;i++)cin>>str[i];unordered_map<string,int>Hash;for(int len=1;len<=n;len++) //枚举长度{int cnt=0;for(int start=1;start+len-1<=n;start++) //枚举起点{string temp="";for(int j=start;j<=start+len-1;j++) //累计枚举区间的字符串temp+=str[j];Hash[temp]++;if(Hash[temp]==1)cnt++;}if(cnt==n-len+1) //说明该长度的所有组合都是第一次出现{cout<<len<<endl;return 0;}}return}
二分还真可以做,需要字符串哈希的我知识,也可以直接用stl
先贴一个代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_set>using namespace std;int n;
string str;
unordered_set<string> S;bool check(int mid)
{S.clear();for (int i = 0; i + mid - 1 < n; i ++ ){string s = str.substr(i, mid);if (S.count(s)) return false;S.insert(s);}return true;
}int main()
{cin >> n >> str;int l = 1, r = n;while (l < r){int mid = l + r >> 1;if (check(mid)) r = mid;else l = mid + 1;}cout << r << endl;return 0;
}
2.双指针
(1)1238. 日志统计

双指针的习题:
思路:先给排序,排序规则:帖子编号从小到大,如果帖子编号一样,则给时间从小到大排序
然后用一个l,r指向一个帖子的区间,判断该帖子是否满足要求,然后判断下一个帖子
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;const int N = 1e5 + 10;int n, d, k;int res[N];
int rc=0;struct node
{int id;int ts;node():id(0),ts(0){}
};node a[N];bool cmp(node &a, node& b)
{if (a.id == b.id)return a.ts < b.ts;return a.id<b.id;
}int main()
{cin >> n >> d >> k;for (int i = 0; i < n; i++)cin >> a[i].ts >> a[i].id;sort(a, a + n, cmp);// for (int i = 0; i < n; i++)// {// cout << a[i].ts << " " << a[i].id << endl;// }//对帖子一个个进行判断//一个指针指向起始时间,一个指向末尾时间int l=0,r=0; //l,r分别是一个帖子的不同时间(开始时间和截至时间)int cnt=0;while(l<n&&r<n){if(a[l].id==a[r].id) //帖子一样{if(a[r].ts-a[l].ts+1<=d){cnt++;r++;}else{l++;cnt--;}if(cnt==k){res[rc++]=a[l].id;cnt=0;int t=a[l].id;while(a[l].id==t)l++;r=l;}}else{l=r;cnt=0;}}for(int i=0;i<rc;i++)cout<<res[i]<<endl;return 0;
}
(2)1240. 完全二叉树的权值

思路:
先将每一层的权值算出来,然后用一个变量res记录最大值。因为层数从小到大遍历,遇到大的才更新,所以可以保证第一次遇到的最大值层数最小。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>using namespace std;typedef long long LL;const int N = 100010;int n;
int a[N];int main()
{scanf("%d", &n);for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);LL maxs = -1e18;int depth = 0;for (int d = 1, i = 1; i <= n; i *= 2, d ++ ){LL s = 0;for (int j = i; j < i + (1 << d - 1) && j <= n; j ++ )s += a[j];cout<<s<<endl;if (s > maxs){maxs = s;depth = d;}}printf("%d\n", depth);return 0;
}
贴上自己第一次写的代码,说明功底还不够
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e6+10;ll a[N];
ll deep[N]; //deep[i]=j表示深度为i的那一层的权值之和为j
int dc=1;int n;struct node
{int d;ll cnt;
};node b[N];bool cmp(node &a,node &b)
{if(a.cnt==b.cnt)return a.d<b.d;return a.cnt>b.cnt;}void count() //计算每一层的个数
{int start=0; //一层的开始int k=1; //一层的个数while(start<=n) //计算每一层的权值{ for(int i=start;i<min(n,start+k);i++){deep[dc]+=a[i];}start+=k;k*=2;dc++;}
}int main()
{cin>>n;for(int i=0;i<n;i++)cin>>a[i];count();// for(int i=1;i<dc;i++)// cout<<deep[i]<<" ";//将每一层的权值之和都算出来就简单了,想怎么做都可以,用一个结构体存下层数和大小,先按大小排序,//cout<<dc<<endl;//如果大小一样,就按照层数排序for(int i=1;i<dc;i++){b[i].d=i;b[i].cnt=deep[i];}sort(b+1,b+dc,cmp);cout<<b[1].d<<endl;return 0;}
(3)字符串删减

思路:
准备工作:
(1)变量ok,遇到x置为true,否则false
(2)left,right指针,left指向第一个遇到的x,right指向最后一个遇到的x
一次遍历即可
#include<iostream>
#include<cstring>using namespace std;const int N=110;int n;
char a[N];
int res=0;int main()
{cin>>n;for(int i=0;i<n;i++)cin>>a[i];int l,r;int sum=0;bool ok=false;for(int i=0;i<n;i++){if(a[i]=='x'){if(!ok){l=r=i;sum=1;ok=true;}else{r++;sum++;}}else{ok=false;if(sum>=3){res+=sum-2;sum=0;}}}if(sum>=3)res+=sum-2;cout<<res<<endl;return 0;}
(4)799. 最长连续不重复子序列

用一个哈希表实时记录出现的元素次数,两个指针指向前后一次遍历即可
#include<iostream>
#include<cstring>
#include<algorithm>
#include<unordered_map>
using namespace std;const int N = 1e5 + 10;int a[N];
int n;int res = 0;int main()
{cin >> n;for (int i = 0; i < n; i++)cin >> a[i];unordered_map<int, int>Hash; //哈希表int l = 0, r = 0;while (l < n && r < n){if (Hash.count(a[r]) == 0 || Hash[a[r]] == 0){Hash[a[r]] = 1;r++;}else{res = max(res, r - l);while (l < n && a[l] != a[r]){Hash[a[l]] = 0;l++;}Hash[a[l]] = 0;l++;}}res=max(res,r-l); //最后一次判断,以免漏掉cout << res;return 0;}
(5)800. 数组元素的目标和

经典双指针,一前一后。用反证法证明不会漏过答案
#include<iostream>
#include<cstring>
using namespace std;const int N=1e5+10;int a[N];
int b[N];int n,m;
int k;int main()
{cin>>n>>m>>k;for(int i=1;i<=n;i++)cin>>a[i];for(int j=1;j<=m;j++)cin>>b[j];int l=1,r=m;bool ok=true;while(ok){if(a[l]+b[r]>k)r--;else if(a[l]+b[r]<k)l++;elseok=false;}cout<<l-1<<" "<<r-1<<endl;return 0;}
(6)判断子序列

#include<iostream>
#include<cstring>
using namespace std;const int N=1e5+10;int n,m;int a[N],b[N];int main()
{cin>>n>>m;for(int i=0;i<n;i++)cin>>a[i];for(int i=0;i<m;i++)cin>>b[i];int i,j;for(i=0,j=0;i<n&&j<m;j++){if(a[i]==b[j])i++;}if(i==n)cout<<"Yes";else cout<<"No";return 0;
}
相关文章:
蓝桥杯训练day2
day21.二分(1)789. 数的范围(2)四平方和(1)哈希表做法(2)二分做法(3)1227. 分巧克力(4)113. 特殊排序(5)1460. 我在哪?2.双指针(1)1238. 日志统计(2)1240. 完全二叉树的权值(3&#…...
为什么99%的程序员都做不好SQL优化?
连接层 最上层是一些客户端和链接服务,包含本地sock 通信和大多数基于客户端/服务端工具实现的类似于 TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程 池的概念,为通过认证安全接入的客户端提供线程。同样…...
Jenkins最新版安装调试
清理旧的jenkins: find / -name jenkins* 一项一项的清理:rm -rf /var/log/jenkins* 下载最新版jenkins镜像:jenkins-redhat-stable安装包下载_开源镜像站-阿里云 上传到服务器: 安装命令: yum install -y jenkins…...
简略说一下go的sync.RWMutex锁
在简略的说之前,首先要对RW锁的结构有一个大致的了解 type RWMutex struct {w Mutex // 写锁互斥锁,只锁写锁,和读锁无关writerSem uint32 // sema锁--用于“写协程”排队等待readerSem uint32 // sema锁--用于“读协程”排队…...
软考马上要报名了,出现这些问题怎么办?
目前,四川、山东、山西、辽宁、河北等地已经率先发布了2023年上半年软考报名通知。 四川:2023年3月13日-4月4日 山东:2023年3月17日9:00-4月3日16:00 山西:2023年3月14日9:00-3月28日11:00 辽宁:2023年3月14日8:30…...
单链表(增删查改)
目录一、什么是单链表?二、单链表的增删查改2.1 结构体变量的声明2.2 申请新结点2.2 链表的头插2.3 链表的尾插2.4 链表的头删2.5 链表的尾删2.6 链表的查找2.7 链表的任意位置后面插入2.8 链表的任意位置后面删除2.9 链表的销毁2.10 链表的打印三、代码汇总3.1 SLi…...
端口复用(bind error: Address already in use 问题)
欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 端口复用专栏:《Linux从小白到大神》《网络编程》 在前面讲解TCP状态转换中提到过一个2MSL…...
数字化引领乡村振兴,VR全景助力数字乡村建设
一、数字乡村建设加速经济发展随着数字化建设的推进,数字化农业产业正在成为农业产业发展的主导力量,因此数字化技术赋予农业产业竞争力的能力不可小觑。数字化乡村建设背景下,数字化信息技术将全面改造升级农村产业,从农业、养殖…...
【数据结构入门】-链表之双向循环链表
个人主页:平行线也会相交 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【数据结构初阶(C实现)】 文章目录链表初始化打印链表尾插尾删新建一个节点头插头删查找在pos之前插入*删除pos位…...
Jenkins自动化部署入门
Jenkins自动化部署入门 一、简介 Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。 Jenkins自动化部署实现原理 二、Jenkins部…...
Springboot 读取模板excel信息内容并发送邮件, 并不是你想想中的那么简单
Springboot 读取模板excel信息内容并发送邮件 背景技术选型搭建过程数据加密隐藏问题暴露背景追溯解决背景 在我们日常开发中, 会遇到这样一种场景, 就是读取表格中的数据, 并将数据以附件的形式通过邮箱发送到表格中的每个人 即: excel 读取 excel 写入 发送邮件(携带附件), 例…...
蓝桥杯真题31日冲刺 |第一天
蓝桥杯真题31日冲刺 |第一天 一:完全平方数 题目:[链接](完全平方数 - 蓝桥云课 (lanqiao.cn)) 思路: 将 每个 完全平方数都 消掉,剩下的就是 不能构成平方的数 以12 为例: 所以 12 只要再 乘个三 即可满足 代…...
STM32开发(18)----CubeMX配置RTC
CubeMX配置RTC前言一、什么是RTC?RTC时钟源RTC备份域二、实验过程1.CubeMX配置2.代码实现3.实验结果总结前言 本章介绍使用STM32CubeMX对RTC进行配置的方法,RTC的原理、概念和特点,配置各个步骤的功能,并通过实验方式验证。 一、…...
Qt 单例模式第一次尝试
文章目录摘要单例模式如何使用Qt 的属性系统总结关键字: Qt、 单例、 的、 Q_GLOBAL_STATIC、 女神节摘要 世界上第一位电脑程序设计师是名女性:Ada Lovelace (1815-1852)是一位英国数学家兼作家,她是第一位主张计算机不只可以用来算数的人…...
C语言--一维数组
数组概念 数组:是一种构造数据类型,用以处理批量的同种类型的数据。 主要特点:数据量大 ,类型相同 一维数组的定义 语法: 类型说明符 数组名[整型常量表达式]; 注意: 方括号里面的内容用于指…...
DataGear 4.5.1 发布,数据可视化分析平台
DataGear 4.5.1 发布,严重 BUG 修复,具体更新内容如下: 修复:修复SQL数据集对于DB2、SQLite等数据源预览时会报错的BUG;修复:修复系统对于MySQL、MariaDB等数据源中无符号数值类型有时报错的BUG࿱…...
Springboot——@valid 做字段校验和自定义注解
文章目录前言注意实现测试环境验证自带的注解自定义valid注解自定义注解和处理类创建参数接收类,并增加字段注解接口中使用自测环节正常测试异常测试自定义全局异常监听扩展递归参数下valid不识别的坑前言 再项目开发中,针对前端传递的参数信息…...
c语言基础练习题详解
💞💞 1.C语言程序的基本单位是(C)。 A.程序行 B. 语句 C. 函数 D.字符 💞💞 2.已知各变量的类型说明如下: int m6,n,a,b; unsigned long w8;…...
C语言设计模式:实现简单工厂模式和工程创建
目录 一,设计模式概念引入 ① 什么是设计模式 ② 什么是类和对象 ③ 什么是工厂模式 二,C语言工厂模式的实现 ① 普通类和对象的代码实现 ② 工厂模式代码实现 ● cat.c ● dog.c ● person.c ● animal.h ● mainpro.c ● 完善mainpro.c …...
3.6日报
今天进行3.0信号整理工作 做官网后台技术文档 了解grpc gRPC是rpc框架中的一种,是rpc中的大哥 是一个高性能,开源和通用的RPC框架,基于Protobuf序列化协议开发,且支持众多开发语言。 面向服务端和协议端,基于http…...
C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
