蓝桥杯一个月准备够吗
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蓝桥杯一个月准备够吗相关的知识,希望对你有一定的参考价值。
一个月的时间相对来说还是比较紧的,要看你的实力了,实力强的话一个月也够了。学习,是指通过阅读、听讲、思考、研究、实践等途径获得知识和技能的过程。学习分为狭义与广义两种:
狭义:通过阅读、听讲、研究、观察、理解、探索、实验、实践等手段获得知识或技能的过程,是一种使个体可以得到持续变化(知识和技能,方法与过程,情感与价值的改善和升华)的行为方式。例如通过学校教育获得知识的过程。
广义:是人在生活过程中,通过获得经验而产生的行为或行为潜能的相对持久为方式。
社会上总会出现一种很奇怪的现象,一些人嘴上埋怨着老板对他不好,工资待遇太低什么的,却忽略了自己本身就是懒懒散散,毫无价值。
自古以来,人们就会说着“因果循环”,这话真不假,你种什么因,就会得到什么果。这就是不好好学习酿成的后果,那么学习有什么重要性呢?
物以类聚人以群分,什么样水平的人,就会处在什么样的环境中。更会渐渐明白自己是什么样的能力。了解自己的能力,交到同水平的朋友,自己个人能力越高,自然朋友质量也越高。
在大多数情况下,学习越好,自身修养也会随着其提升。同样都是有钱人,暴发户摆弄钱财只会让人觉得俗,而真正有知识的人,气质就会很不一样。
高端大气的公司以及产品是万万离不了知识的,只有在知识上不输给别人,才可以在别的地方不输别人。
孩子的教育要从小抓起,家长什么样孩子很大几率会变成什么样。只有将自己的水平提升,才会教育出更好的孩子。而不是一个目光短浅的人。
因为有文化的父母会给孩子带去更多的在成长方面的的帮助,而如果孩子有一个有文化的父母,通常会在未来的道路上,生活得更好,更顺畅。
学习是非常的重要,学习的好坏最终决定朋友的质量、自身修养和后代教育等方面,所以平时在学习中要努力。 参考技术A 0、蓝桥杯介绍
为促进软件和信息领域专业技术人才培养,提升高校毕业生的就业竞争力,由教育部就业指导中心支持,工业和信息化部人才交流中心举办蓝桥杯大赛。十一年来,包括北大、清华在内的超过 1300 余所院校,累计40万余名学子报名参赛,IBM、百度等知名企业全程参与,成为国内始终领跑的人才培养选拔模式并获得行业深度认可的IT类科技竞赛。(官网所说的)
在这里插入图片描述
1、前言
对于刚学完C\C++或java的同学们,想要参加一场比较大型的编程比赛而且还可以给自己提升一些自信心的,那么蓝桥杯软件组便是一个很好的目标,距离第十二届蓝桥杯大赛还有一个多月的时间,但是有好多第一次报名了蓝桥杯的同学们并不知道如何准备,那么本人根据去年疫情在家自学准备蓝桥杯的亲身经验总结出了一些建议给大家,并且告诉大家应该如何在一个月时间内挤进决赛。
本人是在大一时候参加的蓝桥杯软件B组,因为疫情的原因大一下学期全部是在家中度过的,而学校中的C++课程也是以网课的形式来进行教学,所以本人基本是零基础入门编程,之后获得了蓝桥杯软件B组的省一等奖,所以此篇文章主要是写给零基础入门编程、刚刚入门编程没有做过算法题和想在今年的蓝桥杯中获得省一等奖但编程能力并不是很强的同学们(本文章只适合小白,大佬可以不用向下看了)
2、学习资料推荐
2.1网课推荐
(1)完完全全的零基础小白并且想快速对编程进行了解的网课推荐:B站小古银C++入门教程
本人最初在家中学习C++也是看的小古银up主的视频,因为当时对编程了解的非常少再加上大学课程也没有开设C++教学课程,所以只能自学C++,发现好多C++课程都以理论课开始并且有些枯燥有点劝退,直到发现小古银的课程,小古银的课程包括软件安装、基础语法教学、简单编程题的讲解和STL的简单函数的使用,只有十几个小时的课程并且还自带字幕,即使是没有接触过编程的同学们也可以在短时间内学会C++的基础语法并且可以开始自己尝试做算法题。
在这里插入图片描述
(2)已经在大学课程中学会了C\C++的语法基础入门想进一步提高的网课推荐:黑马程序员C++零基础教程
黑马程序员的C++入门课程我认为是一个非常全的C++课程了,课程里面包括基础语法教学、经典算法题、类和对象、文件操作、STL和很多经典小项目的讲解,课程总共52个小时,但是只为蓝桥杯做准备的话课程可以大大缩短,其中的类和对象、文件操作和经典的项目讲解都可以跳过。
在这里插入图片描述
(3)适合零基础算法的同学们的网课:零基础学算法这个网课里面很简短的介绍了大部分基础算法,可以短时间内学会对这些基础算法进行使用。
在这里插入图片描述
(4)蓝桥杯官网每年题解:蓝桥杯官网课程里面有着每年的题解,在比赛前一个星期时候一定要去看看这些题解,了解一下蓝桥杯的大概题型。
2.2算法书推荐
(1)学习起来最为有趣的算法书《啊哈!算法》,此书中讲解了各种排序、栈队列链表、暴力枚举,深搜广搜、最短路径和树等算法,这本书我是在蓝桥杯还有一星期开始时候才知道的一本书,当时看到感觉非常后悔没有早点看到这么好的算法书。基本每天看完一章学习一个到两个算法再做几道相关简单的算法题,半个月的时间就可以冲冲决赛。
在这里插入图片描述
(2)最为经典的算法书《算法竞赛入门经典(第2版)》,这本书虽然写着是入门书,但是完全不适合零基础或者刚刚入门的小白们看,这本书前一半可以在准备蓝桥杯时候看一遍,对里面不是很理解的算法完全可以跳过,因为蓝桥杯大部分题都是暴力枚举,尤其是省赛的时候,好多都并不是真正的算法题,所以只需要看那些能够自己理解的算法题就可以了,但并不是看到不会的算法题就跳过,一定要自己思考半小时左右,如果感觉自己还是理解不了,那这样才可以跳过。
在这里插入图片描述
2.3推荐刷题网站
比赛之前一定要刷完至少四十道的算法题(包括简单题),如果时间充裕还可以继续刷,最好去刷那种两个小时以内能做出来的算法题,不要一道题做一天,可以选择多做一些找规律的题,因为蓝桥杯总是爱出类似“趣味数学题”,这样的题型每年都会出。
(1)信息学奥赛一本通
与小古银相匹配的刷题网站,里面简单的入门题型非常多,对于刚学完基础语法的同学们做这样的题最合适不过了,好多题都是十几分钟就可以做出来的,刷这样的题主要目的就是巩固学习过的语法和对代码的熟练度,因为高中我们就知道学会一个知识点只有做过了相关的题型才知道这个知识具体怎么用(这个网站只适合开始为了熟练代码来进行使用)
(2)计蒜客
这个网站算是设计的比较人性化一些,对于有一些算法基础的同学就可以来这个网站刷题了,刷上十几道题就可以了,因为里面有不同算法的分类,可以进行专项训练。
(3)蓝桥杯练习系统
毕竟是来参加蓝桥杯比赛,对于官网的算法题当然还是要来刷一刷的,本人当时是不知道蓝桥杯还有练习系统,所以知道蓝桥杯前两天才知道有这个系统,所以并没有在这个网站上进行刷很多题。
3、比赛小技巧
3.1题型了解
对于第一次参加编程比赛的同学们,一定要知道蓝桥杯有着五道填空题和五道编程题,对于填空题,基本是可以全部做出来的,但是也可能有一道会难一点,由于蓝桥杯题型多是暴力枚举题型,而且时间又非常充沛,那我们完全可以把编译器当做一个计算器来使用,之后用笔将各种出现的特殊情况记性手写在纸上来分类考虑,就像去年的试题D :跑步训练,这题如果没有思路或者害怕算错,那我们可以用电脑上自带的日历来进行“手算”,将每一年这样的考虑。
对于编程大题,一般前两道题是非常基础的题,一定要做出来并且保证没有特殊情况没有考虑到,因为比赛时候只能提交答案或代码,不知道正误所以一定要保证自己能做出来的题都是正确满分的,蓝桥省赛完全就是比的编程基础,并不需要什么高级算法。
3.2难题的解决办法
因为是比赛,肯定就会有一些难题,那么当我们已经把自己会的题都做完了怎么办呢,我们就应该去看这道题的【评测用例规模与约定】,比如去年的试题H :字串分值,这道题的评测就是
对于20% 的评测用例,1 ≤ n ≤ 10;
对于40% 的评测用例,1 ≤ n ≤ 100;
对于50% 的评测用例,1 ≤ n ≤ 1000;
对于60% 的评测用例,1 ≤ n ≤ 10000;
对于所有评测用例,1 ≤ n ≤ 100000。
虽然我们可能没有思路做出这道题,但是我们可以只考虑1 ≤ n ≤ 100或者1 ≤ n ≤ 10的情况,把这种很少的评测用例来说,我们完全可以用if()语句给出相应答案,这样也可以得出点分数。
4、结尾
对于题目中说的如何混进省一我已经完全把我自己在大一准备蓝桥杯的东西写了出来。我目前也只是一名普通一本大二学生,因为在大一时候参加蓝桥杯只是为了混一个省三等奖,但是结果出来的时候没想到得了一个省一,因为本身在本校ACM战队也是一个小菜鸟,并没有学会很多高级算法,甚至连很多基础算法学的也不是很细,可恰恰蓝桥杯就是考一些暴力枚举基础题型,便成功混到了一个省一。
最后祝大家一个月后都能在蓝桥杯中成功获得省一等奖,能够去北京参加决赛。
文章中有不妥的地方还请指教。 参考技术B 首先如果你目前c和c++都不太熟悉的话,现在就要去熟悉语法和练习了,这里推荐一个网课程序设计与算法(一) ,这是由北大郭炜老师在MOOC上一个开的一个广受好评的教授C和C++讲解程序设计与算法的课程,把这门课的课程和配套习题过一遍基本上语法就熟悉了,然后就可以去看一些算法的资料,可以是书籍,博客,也可以是一些网课。要大致了解常见的动态规划、贪心、搜索、模拟算法,注意要循序渐进。
在有了一定语言和算法基础后最好的准备方式就是去刷蓝桥杯的真题。蓝桥杯官网就可以做,不过那里只有一部分,可以去找找历年的真题。蓝桥杯官方还有对应的题解也可以去看看,如果找不到的话可以搜搜云盘,方法就不用我教了吧,你们都懂。
如果蓝桥杯的题目觉得有些难的话可以去一些oj刷题,新手不建议去leetcode,可以去洛谷,vjudge,百练等平台做题。一类题型做的比较多了就没有必要再做了, 遇到新题或者不会做的题目可以查阅解法,归纳到自己的知识体系当中,看它考了哪些算法和知识点。有不会的算法就去查一查,如果能弄懂最好用电子笔记记录下来。弄不懂不要死磕。
在时间管理上,准备蓝桥杯大约要一个月左右的时间,最好每天都能抽出一到两小时去写代码,学算法。准备编程类的竞赛一定不能光看不练,要多练多实践才能变强。
acwing蓝桥杯
写在前面
距离这届蓝桥杯已经过了八个月了,一直没总结算法,实在是太懒了,懒狗一条…
考前看知乎上说蓝桥杯一个月准备可以拿省一,当时还真信了,不过也可能是我有点懒,准备也不够一个月,没有专门投入太多,刷的题也不多,后面快考的时候直接摆烂了,觉得可能没啥希望,就随便看看真题了,最后就拿了个江苏CA省二,排位大概省二中上一点的样子,聊胜于无吧,没啥意思,我只想说,***退钱!!!
如果没啥竞赛基础的同学建议先看一下胡凡的《算法笔记》,这本书挺适合入门的,可以了解到算法竞赛中的大致考点,看完后就可以直接对应刷题了,如果时间不是很充足的话我个人不是很建议看紫书蓝书这种纯竞赛书,会花很多时间,而且考点是不太一样的,建议就刷acwing的蓝桥杯专题,然后多刷真题,真题就已经很多了,真题可以到官网上找,或者去一些oj也行,当时还看了罗老师的蓝桥杯每日一题https://blog.csdn.net/weixin_43914593/category_10721247.html挺不错的。不建议单纯刷力扣来准备,力扣上的用stl比较多,竞赛上更多的是用数组模拟,而且两者的侧重不同,力扣上更侧重解决的方法,只需要写solve函数就行,算法竞赛还需要自己注意输入输出格式的转换等等,当然用它复习知识点是可以的。
之前蓝桥杯搜索题很多,也“暴力杯”,但现在也越来越多动态规划题了,感觉蓝桥杯越来越难了,不太能随便混奖了,这就是内卷的结果吗…
蓝桥杯c++是可以用万能头的,而且看样例通过数给分,可以打表或者暴力骗点分,该骗的时候一定要骗,不要硬磕,也不要啥都不写(大佬直接忽略),写题的时候可以记录下思路整理到笔记,也方便以后看看,我就没写,所以下面题解都没啥讲解思路,刷题途中可能会遇到一些库的用法不太熟悉,或者一些转换的骚操作一定要单独记到笔记上面,方便复习查看。
这种编程算法还是要多敲的,一段时间不敲连二分都敲不利索,而且还有一些模板题啥的也要靠理解记忆,太长时间不敲是真不太行,手感还是很重要的,怎么说呢,个人还是更喜欢ctf和ai这种竞赛,可以翻阅笔记在线搜索啥的,不用在死板的东西上花太多时间去记忆。
明年的蓝桥杯本来也是打算报一下的,但想到四五月份可能准备考研了,时间不太充裕,这种算法又太依赖刷题和当时手感,不如就打打ctf算了。当然还有一个重要原因,300报名费还是太贵了…
第一讲 递归与递推
92. 递归实现指数型枚举
从 1∼n 这 n 个整数中随机选取任意多个,输出所有可能的选择方案。
输入格式
输入一个整数 n。
输出格式
每行输出一种方案。
同一行内的数必须升序排列,相邻两个数用恰好 1 个空格隔开。
对于没有选任何数的方案,输出空行。
本题有自定义校验器(SPJ),各行(不同方案)之间的顺序任意。
数据范围
1≤n≤15
输入样例:
3
输出样例:
3
2
2 3
1
1 3
1 2
1 2 3
#include<bits/stdc++.h>
using namespace std;
bool st[20];
int i,n;
void dfs(int x)
if(x>n)
for(i=1;i<=n;i++)
if(st[i])
cout<<i<<" ";
cout<<endl;
return;
st[x]=true;
dfs(x+1);
st[x]=false;
dfs(x+1);
int main()
cin>>n;
dfs(1);
return 0;
94. 递归实现排列型枚举
把 1∼n1∼n 这 nn 个整数排成一行后随机打乱顺序,输出所有可能的次序。
输入格式
一个整数 nn。
输出格式
按照从小到大的顺序输出所有方案,每行 11 个。
首先,同一行相邻两个数用一个空格隔开。
其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面。
数据范围
1≤n≤91≤n≤9
输入样例:
3
输出样例:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
#include<bits/stdc++.h>
using namespace std;
int vis[20],book[20],n;
void dfs(int x)
if(x>n)
for(int i=1;i<=n;i++)
cout<<book[i]<<" ";
cout<<endl;
return;
for(int i=1;i<=n;i++)
if(vis[i]==0)
book[x]=i;
vis[i]=1;
dfs(x+1);
vis[i]=0;
int main()
cin>>n;
dfs(1);
return 0;
717. 简单斐波那契
以下数列 0 1 1 2 3 5 8 13 21 ...
被称为斐波纳契数列。
这个数列从第 33 项开始,每一项都等于前两项之和。
输入一个整数 N,请你输出这个序列的前 N 项。
输入格式
一个整数 N。
输出格式
在一行中输出斐波那契数列的前 N 项,数字之间用空格隔开。
数据范围
0<N<46
输入样例:
5
输出样例:
0 1 1 2 3
//递归带剪枝(备忘录)
#include<bits/stdc++.h>
using namespace std;
int N[50];
int fib(int n)
if(N[n]) return N[n];
if(n==0) return 0;
if(n==1||n==2) return 1;
N[n]=fib(n-1)+fib(n-2);
return N[n];
int main()
int n;
N[0]=0,N[1]=1,N[2]=1;
cin>>n;
fib(n-1);
for(int i=0;i<n;i++) cout<<N[i]<<" ";
return 0;
//不用数组直接输出
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
int a = 0, b = 1;
int n;
cin >> n;
for (int i = 0; i < n; i ++ )
cout << a << ' ';
int c = a + b;
a = b, b = c;
cout << endl;
return 0;
95. 费解的开关
你玩过“拉灯”游戏吗?
25 盏灯排成一个 5×5 的方形。
每一个灯都有一个开关,游戏者可以改变它的状态。
每一步,游戏者可以改变某一个灯的状态。
游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也要相应地改变其状态。
我们用数字 11 表示一盏开着的灯,用数字 00 表示关着的灯。
下面这种状态
10111
01101
10111
10000
11011
在改变了最左上角的灯的状态后将变成:
01111
11101
10111
10000
11011
再改变它正中间的灯后状态将变成:
01111
11001
11001
10100
11011
给定一些游戏的初始状态,编写程序判断游戏者是否可能在 66 步以内使所有的灯都变亮。
输入格式
第一行输入正整数 n,代表数据中共有 n 个待解决的游戏初始状态。
以下若干行数据分为 n 组,每组数据有 5 行,每行 5 个字符。
每组数据描述了一个游戏的初始状态。
各组数据间用一个空行分隔。
输出格式
一共输出 n 行数据,每行有一个小于等于 6 的整数,它表示对于输入数据中对应的游戏状态最少需要几步才能使所有灯变亮。
对于某一个游戏初始状态,若 66步以内无法使所有灯变亮,则输出 −1。
数据范围
0<n≤5000
输入样例:
3
00111
01011
10001
11010
11100
11101
11101
11110
11111
11111
01111
11111
11111
11111
11111
输出样例:
3
2
-1
//二进制模拟枚举 本行的状态都通过下一行的改变而改变
#include<bits/stdc++.h>
using namespace std;
const int N = 6;
char g[N][N], backup[N][N];
int dx[5] = -1, 0, 1, 0, 0, dy[5] = 0, 1, 0, -1, 0;
void turn(int x, int y)
for (int i = 0; i < 5; i ++ )
int a = x + dx[i], b = y + dy[i];
if (a < 0 || a >= 5 || b < 0 || b >= 5) continue; // 在边界外,直接忽略即可
g[a][b] ^= 1;//异或,同0异1,与1异或则状态改变
int main()
int T;
cin >> T;
while (T -- )
for (int i = 0; i < 5; i ++ ) cin >> g[i];
int res = 10;
for (int op = 0; op < 32; op ++ ) //32为第一行所有不同的按法,
memcpy(backup, g, sizeof g);
int step = 0;
for (int i = 0; i < 5; i ++ )
if (op >> i & 1)//
step ++ ;
turn(0, i);
for (int i = 0; i < 4; i ++ )
for (int j = 0; j < 5; j ++ )
if (g[i][j] == '0')
step ++ ;
turn(i + 1, j);//按同列的下一行即可将此处的0变为1
bool dark = false;
for (int i = 0; i < 5; i ++ )//如果最后一行全是1则成功
if (g[4][i] == '0')
dark = true;
break;
if (!dark) res = min(res, step);
memcpy(g, backup, sizeof g);
if (res > 6) res = -1;
cout << res << endl;
return 0;
93. 递归实现组合型枚举
从 1∼n这 n 个整数中随机选出 m 个,输出所有可能的选择方案。
输入格式
两个整数 n,m ,在同一行用空格隔开。
输出格式
按照从小到大的顺序输出所有方案,每行 1 个。
首先,同一行内的数升序排列,相邻两个数用一个空格隔开。
其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面(例如 1 3 5 7
排在 1 3 6 8
前面)。
数据范围
n>0
0≤m≤n,
n+(n−m)≤25
输入样例:
5 3
输出样例:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
思考题:如果要求使用非递归方法,该怎么做呢?
#include<bits/stdc++.h>
using namespace std;
int res[20];
int a,b;
void dfs(int max,int num,int n,int a)
if(a==num)
for(int x=0;x<num;x++)
cout<<res[x]<<" ";
cout<<endl;
return;
for(int i=n;i<=max;i++)
res[a]=i;
dfs(max,num,i+1,a+1);
int main()
cin>>a>>b;
dfs(a,b,1,0);
return 0;
1209. 带分数
100100 可以表示为带分数的形式:100=3+69258/714
还可以表示为:100=82+3546/197
注意特征:带分数中,数字 1∼91∼9 分别出现且只出现一次(不包含 00)。
类似这样的带分数,100100 有 1111 种表示法。
输入格式
一个正整数。
输出格式
输出输入数字用数码 1∼9 不重复不遗漏地组成带分数表示的全部种数。
数据范围
1≤N<106
输入样例1:
100
输出样例1:
11
输入样例2:
105
输出样例2:
6
#include<bits/stdc++.h>
using namespace std;
const int N=10;
int num[N];
bool used[N];
int target;
int cnt=0;
int calc(int l,int r)
int res=0;
for(int i=l;i<=r;i++)
res=res*10+num[i];
return res;
void dfs(int s)
if(s==9)
for(int i=1;i<=6;i++)
for(int j=i+1;j<=8;j++)
int a = calc(1, i);
int b = calc(i + 1, j);
int c = calc(j + 1, 9);
if(a * c + b == c * target) cnt++;
return;
for(int i=1;i<10;i++)
if(!used[i])
used[i]=true;
num[s+1]=i;
dfs(s+1);
used[i]=false;
int main()
cin>>target;
dfs(0);
cout<<cnt;
return 0;
1208. 翻硬币
小明正在玩一个“翻硬币”的游戏。
桌上放着排成一排的若干硬币。我们用 * 表示正面,用 o 表示反面(是小写字母,不是零)。
比如,可能情形是:**oo***oooo
如果同时翻转左边的两个硬币,则变为:oooo***oooo
现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币,那么对特定的局面,最少要翻动多少次呢?
我们约定:把翻动相邻的两个硬币叫做一步操作。
输入格式
两行等长的字符串,分别表示初始状态和要达到的目标状态。
输出格式
一个整数,表示最小操作步数
数据范围
输入字符串的长度均不超过100。
数据保证答案一定有解。
输入样例1:
**********
o****o****
输出样例1:
5
输入样例2:
*o**o***o***
*o***o**o***
输出样例2:
1
#include<bits/stdc++.h>//从头搜索,翻转不一样位置的后面的硬币不能对此位置造成影响,翻前一个则会打乱前面相同的字符,产生新的不同字符,所以最优就是翻此硬币(贪心)
using namespace std;
int main()
string start,target;
int step=0;
cin>>start>>target;
int n=start.size();
for(int i=0;i<n-1;i++)
if(start[i]!=target[i])
if(start[i]=='*') start[i]='o';
else start[i]='*';
if(start[i+1]=='*') start[i+1]='o';
else start[i+1]='*';
step++;
cout<<step;
return 0;
116. 飞行员兄弟
“飞行员兄弟”这个游戏,需要玩家顺利的打开一个拥有 16 个把手的冰箱。
已知每个把手可以处于以下两种状态之一:打开或关闭。
只有当所有把手都打开时,冰箱才会打开。
把手可以表示为一个 4×4的矩阵,您可以改变任何一个位置 [i,j][i,j] 上把手的状态。
但是,这也会使得第 i 行和第 jj列上的所有把手的状态也随着改变。
请你求出打开冰箱所需的切换把手的次数最小值是多少。
输入格式
输入一共包含四行,每行包含四个把手的初始状态。
符号 +
表示把手处于闭合状态,而符号 -
表示把手处于打开状态。
至少一个手柄的初始状态是关闭的。
输出格式
第一行输出一个整数 N,表示所需的最小切换把手次数。
接下来 N 行描述切换顺序,每行输出两个整数,代表被切换状态的把手的行号和列号,数字之间用空格隔开。
注意:如果存在多种打开冰箱的方式,则按照优先级整体从上到下,同行从左到右打开。
数据范围
1≤i,j≤4
输入样例:
-+--
----
----
-+--
输出样例:
6
1 1
1 3
1 4
4 1
4 3
4 4
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N = 4, INF = 100;
int change[N][N];
int get(int x, int y)
return x * 4 + y;
int main()
for (int i = 0; i < N; i ++ )
for (int j = 0; j < N; j ++ )
for (int k = 0; k < N; k ++ ) change[i][j] += (1 << get(i, k)) + (1 << get(k, j));
change[i][j] -= 1 << get(i, j);
int state = 0;
for (int i = 0; i < N; i ++ )
string line;
cin >> line;
for (int j = 0; j < N; j ++ )
if (line[j] == '+')
state += 1 << get(i, j);
vector<PII> path;
for (int i = 0; i < 1 << 16; i ++ )//枚举按下的所有情况(位置一样即可,先后顺序不影响)
int now = state;
vector<PII> temp;
for (int j = 0; j < 16; j ++ )
if (i >> j & 1)
int x = j / 4, y = j % 4;
now ^= change[x][y];
temp.push_back(x, y);
if (!now && (path.empty() || path.size() > temp.size())) path = temp;
cout << path.size() << endl;
for (auto &p : path)
cout << p.first + 1 << ' ' << p.second + 1 << endl;
return 0;
第二讲 二分与前缀和
789. 数的范围
给定一个按照升序排列的长度为 n的整数数组,以及 q个查询。
对于每个查询,返回一个元素 k 的起始位置和终止位置(位置从 0 开始计数)。
如果数组中不存在该元素,则返回 -1 -1
。
输入格式
第一行包含整数 n 和 q,表示数组长度和询问个数。
第二行包含 n 个整数(均在 1∼10000 范围内),表示完整数组。
接下来 q 行,每行包含一个整数 k,表示一个询问元素。
输出格式
共 q 行,每行包含两个整数,表示所求元素的起始位置和终止位置。
如果数组中不存在该元素,则返回 -1 -1
。
数据范围
1≤n≤100000
1≤q≤10000
1≤k≤10000
输入样例:
6 3
1 2 2 3 3 4
3
4
5
输出样例:
3 4
5 5
-1 -1
难度:简单 |
---|
时/空限制:1s / 64MB |
总通过数:32991 |
总尝试数:54013 |
来源:模板题,AcWing |
算法标签二分 |
#include<iostream>
using namespace std;
const int N=100010;
int q[N];
int main()
int n,c,x;
cin>>n>>c;
for(int i=0;i<n;i++) cin>>q[i];
while(c--)
cin>>x;
int l=0,r=n-1;
while(l<r)
int mid=l+r>>1;
if(q[mid]<x) l=mid+1;
else r=mid;
if(q[l]!=x)
cout<<"-1 -1"<<endl;
continue;
int l1 = l, r1 = n-1;
while(l1<r1)
int mid=l1+r1+1>>1;
if(q[mid]<=x) l1=mid;
else r1=mid-1;
cout<<l<<" "<<l1<<endl;
return 0;
整数二分算法模板 —— 模板题 AcWing 789. 数的范围
bool check(int x) /* ... */ // 检查x是否满足某种性质
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
while (l < r)
int mid = l + r >> 1;
if (check(mid)) r = mid; // check()判断mid是否满足性质
else l = mid + 1;
return l;
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
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;
浮点数二分算法模板 —— 模板题 AcWing 790. 数的三次方根
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;
return l;
790. 数的三次方根
给定一个浮点数 n,求它的三次方根。
输入格式
共一行,包含一个浮点数 n。
输出格式
共一行,包含一个浮点数,表示问题的解。
注意,结果保留 6 位小数。
数据范围
−10000≤n≤10000
输入样例:
1000.00
输出样例:
10.000000
难度:简单 |
---|
时/空限制:1s / 64MB |
总通过数:23870 |
总尝试数:45712 |
来源:模板题,AcWing |
算法标签二分 |
#include<iostream>
#include<iomanip>
using namespace std;
double l,r,mid,n;
double thr(double n)
return n*n*n;
int main()
cin>>n;
l=-25, r=25;
while(r-l>1e-7)
mid=(l+r)/2;
if(thr(mid)>=n) r=mid;
else l=mid;
cout<<fixed<<setprecision(6)<<l;
return 0;
730. 机器人跳跃问题
机器人正在玩一个古老的基于 DOS 的游戏。
游戏中有 N+1座建筑——从 0 到 N 编号,从左到右排列。
编号为 0 的建筑高度为 0 个单位,编号为 i 的建筑高度为 H(i) 个单位。
起初,机器人在编号为 0 的建筑处。
每一步,它跳到下一个(右边)建筑。
假设机器人在第 k 个建筑,且它现在的能量值是 E,下一步它将跳到第k+1 个建筑。
如果 H(k+1)>E,那么机器人就失去 H(k+1)−E的能量值,否则它将得到 E−H(k+1) 的能量值。
游戏目标是到达第 N 个建筑,在这个过程中能量值不能为负数个单位。
现在的问题是机器人至少以多少能量值开始游戏,才可以保证成功完成游戏?
输入格式
第一行输入整数 N。
第二行是 N 个空格分隔的整数,H(1),H(2),…,H(N) 代表建筑物的高度。
输出格式
输出一个整数,表示所需的最少单位的初始能量值上取整后的结果。
数据范围
1≤N,H(i)≤10^5
输入样例1:
5
3 4 3 2 4
输出样例1:
4
输入样例2:
3
4 4 4
输出样例2:
4
输入样例3:
3
1 6 4
输出样例3:
3
难度:中等 |
---|
时/空限制:3s / 64MB |
总通过数:4344 |
总尝试数:9691 |
来源:今日头条2019,笔试题 |
算法标签二分递推 |
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n;
int h[N];
bool check(int mid)
for(int i=1;i<=n;i++)
mid+=mid-h[i];
if (mid>= 1e5) return true; //防止int溢出
if(mid<0) return false;
return true;
int main()
cin>>n;
for(int i=1;i<=n;i++)
cin>>h[i];
int l=0,r=1e5;
while(l<r)
int mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
cout<<l;
return 0;
1221. 四平方和
四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多 4 个正整数的平方和。
如果把 00 包括进去,就正好可以表示为 4 个数的平方和。
比如:
5=02+02+12+22
7=12+12+12+22
对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对 4 个数排序:
0≤a≤b≤c≤d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法。
输入格式
输入一个正整数 N。
输出格式
输出4个非负整数,按从小到大排序,中间用空格分开。
数据范围
0<N<5∗1060<N<5∗106
输入样例:
5
输出样例:
0 0 1 2
难度:简单 |
---|
时/空限制:1s / 64MB |
总通过数:3882 |
总尝试数:14618 |
来源:第七届蓝桥杯省赛C++A/B组,第七届蓝桥杯省赛JAVAB/C组 |
算法标签二分 哈希 |
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 2500010;
struct Sum
int s, c, d;
bool operator< (const Sum &t)const //重定义后可使用sort
if (s != t.s) return s < t.s;
if (c != t.c) return c < t.c;
return d < t.d;
sum[N];
int n, 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 = 0; a * a + b * b <= n; b ++ )
int t = n - a * a - b * b;
int l = 0, r = m - 1;
while (l < r)
int mid = l + r >> 1;
if (sum[mid].s >= t) r = mid;
else l = mid + 1;
if (sum[l].s == t)
printf("%d %d %d %d\\n", a, b, sum[l].c, sum[l].d);
return 0;
return 0;
1227. 分巧克力
儿童节那天有 K 位小朋友到小明家做客。
小明拿出了珍藏的巧克力招待小朋友们。
小明一共有 N 块巧克力,其中第 ii 块是 Hi×Wi的方格组成的长方形。
为了公平起见,小明需要从这 N 块巧克力中切出 K 块巧克力分给小朋友们。
切出的巧克力需要满足:
- 形状是正方形,边长是整数
- 大小相同
例如一块 6×5的巧克力可以切出 6 块 2×2的巧克力或者 2 块 3×3的巧克力。
当然小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少么?
输入格式
第一行包含两个整数 N 和 K。
以下 N 行每行包含两个整数 Hi和 Wi。
输入保证每位小朋友至少能获得一块 1×1 的巧克力。
输出格式
输出切出的正方形巧克力最大可能的边长。
数据范围
1≤N,K≤10^5
1≤Hi,Wi≤10^5
输入样例:
2 10
6 5
5 6
输出样例:
2
难度:简单 |
---|
时/空限制:1s / 64MB |
总通过数:7643 |
总尝试数:15754 |
来源:第八届蓝桥杯省赛C++A/B组,第八届蓝桥杯省赛JAVAA/B组 |
算法标签二分 |
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int h[N],w[N];
int n,k;
bool check(int mid)
int res=0;
for(int i=0;i<n;i++)
res+=(h[i]/mid)*(w[i]/mid);
if(res>=k) return true;
else return false;
int main()
ios::sync_with_stdio(false);
cin>>n>>k;
for(int i=0;i<n;i++)
cin>>h[i]>>w[i];
int l=0,r=1e5;
while(l<r)
int mid=l+r+1>>1;
if(check(mid)) l=mid;
else r=mid-1;
cout<<l;
return 0;
99. 激光炸弹
地图上有 N 个目标,用整数 Xi,Yi表示目标在地图上的位置,每个目标都有一个价值 Wi。
注意:不同目标可能在同一位置。
现在有一种新型的激光炸弹,可以摧毁一个包含 R×R 个位置的正方形内的所有目标。
激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆炸范围,即那个正方形的边必须和 x,y 轴平行。
求一颗炸弹最多能炸掉地图上总价值为多少的目标。
输入格式
第一行输入正整数 N 和 R,分别代表地图上的目标数目和正方形的边长,数据用空格隔开。
接下来 N 行,每行输入一组数据,每组数据包括三个整数 Xi,Yi,Wi,分别代表目标的 x 坐标,y 坐标和价值,数据用空格隔开。
输出格式
输出一个正整数,代表一颗炸弹最多能炸掉地图上目标的总价值数目。
数据范围
0≤R≤10^9
0<N≤10000
0≤Xi,Yi≤5000
0≤Wi≤1000
输入样例:
2 1
0 0 1
1 1 1
输出样例:
1
难度:简单 |
---|
时/空限制:1s / 168MB |
总通过数:8583 |
总尝试数:25487 |
来源:《算法竞赛进阶指南》, HNOI2003 |
算法标签二维前缀和 |
#include <iostream>
using namespace std;
int g[5010][5010];//价值
int N,R;
int main()
cin>>N>>R;
int n=R,m=R;//长和宽
for(int i=0,x,y,w;i<N;i++)
cin>>x>>y>>w;
x++;
y++;
//为了方便处理边界,把前缀和定义从1开始,所以开头要++
n=max(n,x);
m=max(m,y);
//判断长和宽的边界
g[x][y]+=w;//将他们的价值放进数组里
//输入&预处理
n = 5001, m = 5001, R = min(R, 5001);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
g[i][j]+=g[i-1][j] + g[i][j-1] -g[i-1][j-1];
//g[i-1][j]=sum1,g[i][j-1]=sum2,g[i-1][j-1]=sum3
//求二维前缀和
int ans=0;
for(int i=R;i<=n;i++)//长
for(int j=R;j<=m;j++)//宽
ans=max(ans,g[i][j] - g[i-R][j] - g[i][j-R] +g[i-R][j-R]);
//求最大值
cout<<ans<<endl;
return 0;
1230. K倍区间
给定一个长度为 N 的数列,A1,A2,…AN,如果其中一段连续的子序列 Ai,Ai+1,…Aj 之和是 K 的倍数,我们就称这个区间 [i,j][i,j] 是 K 倍区间。
你能求出数列中总共有多少个 K 倍区间吗?
输入格式
第一行包含两个整数 N 和 K。
以下 N 行每行包含一个整数 Ai。
输出格式
输出一个整数,代表 K 倍区间的数目。
数据范围
1≤N,K≤100000
1≤Ai≤100000
输入样例:
5 2
1
2
3
4
5
输出样例:
6
难度:中等 |
---|
时/空限制:1s / 64MB |
总通过数:4754 |
总尝试数:12418 |
来源:第八届蓝桥杯省赛C++B组,第八届蓝桥杯省赛JAVAB组 |
算法标签前缀和 |
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010;
int n, k;
LL s[N], cnt[N];
int main()
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i ++ )
scanf("%lld", &s[i]);
s[i] += s[i - 1];
LL res = 0;
cnt[0] = 1;
for (int i = 1; i <= n; i ++ )
res += cnt[s[i] % k];
cnt[s[i] % k] ++ ;
printf("%lld\\n", res);
return 0;
第三讲 数学与简单DP
1205. 买不到的数目
小明开了一家糖果店。
他别出心裁:把水果糖包成4颗一包和7颗一包的两种。
糖果不能拆包卖。
小朋友来买糖的时候,他就用这两种包装来组合。
当然有些糖果数目是无法组合出来的,比如要买 10 颗糖。
你可以用计算机测试一下,在这种包装情况下,最大不能买到的数量是17。
大于17的任何数字都可以用4和7组合出来。
本题的要求就是在已知两个包装的数量时,求最大不能组合出的数字。
输入格式
两个正整数 n,m表示每种包装中糖的颗数。
输出格式
一个正整数,表示最大不能买到的糖数。
数据范围
2≤n,m≤1000
保证数据一定有解。
输入样例:
4 7
输出样例:
17
难度:简单 |
---|
时/空限制:1s / 64MB |
总通过数:3821 |
总尝试数:6647 |
来源:第四届蓝桥杯省赛C++A组,第四届蓝桥杯省赛JAVAC组 |
算法标签数论结论题 |
//数论题,可打表找规律
#include <iostream>
using namespace std;
int main()
int p, q;
cin >> p >> q;
cout << (p - 1) * (q - 1) - 1 << endl;
return 0;
1211. 蚂蚁感冒
长 100厘米的细长直杆子上有 n 只蚂蚁。
它们的头有的朝左,有的朝右。
每只蚂蚁都只能沿着杆子向前爬,速度是 1 厘米/秒。
当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行。
这些蚂蚁中,有 1 只蚂蚁感冒了。
并且在和其它蚂蚁碰面时,会把感冒传染给碰到的蚂蚁。
请你计算,当所有蚂蚁都爬离杆子时,有多少只蚂蚁患上了感冒。
输入格式
第一行输入一个整数 n, 表示蚂蚁的总数。
接着的一行是 n 个用空格分开的整数 XiXi, 的绝对值表示蚂蚁离开杆子左边端点的距离。
正值表示头朝右,负值表示头朝左,数据中不会出现 0 值,也不会出现两只蚂蚁占用同一位置。
其中,第一个数据代表的蚂蚁感冒了。
输出格式
输出1个整数,表示最后感冒蚂蚁的数目。
数据范围
1<n<50
0<|Xi|<100
输入样例1:
3
5 -2 8
输出样例1:
1
输入样例2:
5
-10 8 -20 12 25
输出样例2:
3
难度:简单 |
---|
时/空限制:1s / 64MB |
总通过数:2799 |
总尝试数:5471 |
来源:第五届蓝桥杯省赛C++A/B组 |
算法标签数学 |
//由于碰面后速度都不变,可以看作感染后不掉头,还是按原来的方向走
#include<bits/stdc++.h>
using namespace std;
const int N = 55;
int x[N];
int main()
ios::sync_with_stdio(false);
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>x[i];
int res=1;
int flag=0;
int right=0;
if(x[0]>0)
for(int i=1;i<n;i++)
if(x[i]<0&&abs(x[i])>x[0])
res++;
flag=1;
if(x[i]>0&&x[i]<x[0]) right++;
if(flag) res+=right;
else
for(int i=1;i<n;i++)
if(x[i]>0&&x[i]<abs(x[0]))
res++;
flag=1;
if(x[i]<0&&x[i]<x[0]) right++;
if(flag) res+=right;
cout<<res;
return 0;
1216. 饮料换购
乐羊羊饮料厂正在举办一次促销优惠活动。乐羊羊C型饮料,凭3个瓶盖可以再换一瓶C型饮料,并且可以一直循环下去(但不允许暂借或赊账)。
请你计算一下,如果小明不浪费瓶盖,尽量地参加活动,那么,对于他初始买入的 n 瓶饮料,最后他一共能喝到多少瓶饮料。
输入格式
输入一个整数 n,表示初始买入的饮料数量。
输出格式
输出一个整数,表示一共能够喝到的饮料数量。
数据范围
0<n<10000
输入样例:
100
输出样例:
149
难度:简单 |
---|
时/空限制:1s / 64MB |
总通过数:2875 |
总尝试数:4171 |
来源:第六届蓝桥杯省赛C++A/C组,第六届蓝桥杯省赛JAVAB组 |
算法标签数学 |
#include <iostream>
using namespace std;
int main()
int n;
cin >> n;
int res = n;
while (n >= 3)
res += n / 3;
n = n / 3 + n % 3;
cout << res << endl;
return 0;
2. 01背包问题
有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。
第 ii 件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,N,V用空格隔开,分别表示物品数量和背包容积。
接下来有 NN 行,每行两个整数 vi,wi,用空格隔开,分别表示第 ii 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤1000
0<vi,wi≤1000
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
8
难度:简单 |
---|
时/空限制:1s / 64MB |
总通过数:59912 |
总尝试数:101193 |
来源:背包九讲 , 模板题 |
算法标签背包问题DP |
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int dp[N][N],val[N],r[N];
int n,v;
int main()
cin>>n>>v;
for(int i=1;i<=n;i++)
cin>>r[i]>>val[i];
for(int i=1;i<=n;i++)
for(int w=1;w<=v;w++)
if(w-r[i]<0) dp[i][w]=dp[i-1][w];
else
dp[i][w]=max(dp[i-1][w],dp[i-1][w-r[i]]+val[i]);
cout<<dp[n][v];
return 0;
1015. 摘花生
Hello Kitty想摘点花生送给她喜欢的米老鼠。
她来到一片有网格状道路的矩形花生地(如下图),从西北角进去,东南角出来。
地里每个道路的交叉点上都有种着一株花生苗,上面有若干颗花生,经过一株花生苗就能摘走该它上面所有的花生。
Hello Kitty只能向东或向南走,不能向西或向北走。
问Hello Kitty最多能够摘到多少颗花生。
输入格式
第一行是一个整数T,代表一共有多少组数据。
接下来是T组数据。
每组数据的第一行是两个整数,分别代表花生苗的行数R和列数 C。
每组数据的接下来R行数据,从北向南依次描述每行花生苗的情况。每行数据有C个整数,按从西向东的顺序描述了该行每株花生苗上的花生数目M。
输出格式
对每组输入数据,输出一行,内容为Hello Kitty能摘到得最多的花生颗数。
数据范围
1≤T≤100
1≤R,C≤100
0≤M≤1000
输入样例:
2
2 2
1 1
3 4
2 3
2 3 4
1 6 5
输出样例:
8
16
难度:简单 |
---|
时/空限制:1s / 64MB |
总通过数:9825 |
总尝试数:12373 |
来源:《信息学奥赛一本通》 |
算法标签DP线性DP |
#include<bits/stdc++.h>
using namespace std;
const int N=110;
int s[N][N],dp[N][N];
int main()
int t;
cin>>t;
while(t--)
int m,n;
cin>>m>>n;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
cin>>s[i][j];
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
dp[i][j]=max(dp[i-1][j],dp[i][j-1])+s[i][j];
cout<<dp[m][n]<<endl;
return 0;
895. 最长上升子序列
给定一个长度为 N 的数列,求数值严格单调递增的子序列的长度最长是多少。
输入格式
第一行包含整数 N。
第二行包含 N 个整数,表示完整序列。
输出格式
输出一个整数,表示最大长度。
数据范围
1≤N≤1000
−109≤数列中的数≤109
输入样例:
7
3 1 2 1 8 5 6
输出样例:
4
难度:简单 |
---|
时/空限制:1s / 64MB |
总通过数:16296 |
总尝试数:24724 |
来源:模板题,AcWing |
算法标签动态规划线性DP最长上升子序列 |
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int dp[N],s[N];
int n;
int main()
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>s[i];
dp[1]=1;
int res=0;
for(int i=2;i<=n;i++)
dp[i]=1;
for(int j=1;j<i;j++)
if(s[j]<s[i]) dp[i]=max(dp[i],dp[j]+1);
res=max(res,dp[i]);
cout<<res;
return 0;
1212. 地宫取宝
X 国王有一个地宫宝库,是 n×m 个格子的矩阵,每个格子放一件宝贝,每个宝贝贴着价值标签。
地宫的入口在左上角,出口在右下角。
小明被带到地宫的入口,国王要求他只能向右或向下行走。
走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。
当小明走到出口时,如果他手中的宝贝恰好是 k 件,则这些宝贝就可以送给小明。
请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这 k 件宝贝。
输入格式
第一行 3 个整数,n,m,k,含义见题目描述。
接下来 n 行,每行有 m 个整数 Ci 用来描述宝库矩阵每个格子的宝贝价值。
输出格式
输出一个整数,表示正好取 k 个宝贝的行动方案数。
该数字可能很大,输出它对 1000000007取模的结果。
数据范围
1≤n,m≤50
1≤k≤12
0≤Ci≤12
输入样例1:
2 2 2
1 2
2 1
输
以上是关于蓝桥杯一个月准备够吗的主要内容,如果未能解决你的问题,请参考以下文章