大家好,我是程序员蛟龙哥,昨年勉强混进省二,哎哭了,这次俺一定省一,淦。这篇就来全面梳理蓝桥的技巧,以及我的一点点经验,以及基础的代码模板,希望能帮你考场上多拿几分。
著名律师查理芒格曾经说过避免失败是成功的捷径
ACM大佬略过,所以每个人的状态不同,不是上来就能拿国奖的,找准自己定位,打牢基础才是重点,重点是一定不要盲目刷题,做完之后要思考为啥考的是这个数据结构。这组好像是有相似的特点,就能多余抽去剩下结构进行复用,后面也会总结常见的模板供你使用,全程干货,记得收藏点个赞啥的。
🎨 一 技巧篇
1 结果填空题
首先判断能不能借助日历、计算器、WPS、txt文本、Notepad++或者数学方法等工具进行快速解出来,最后再选择用Eclipse代码暴力破解。有的填空题可能是没有思路,可以尝试一下手算,算这算这有思路了呢。
2 代码填空题
这种一般是递归、找规律等,实在想不出来可以随便试,可以猜常见的数字哈哈。先通过多组数据样本填空测试输出结果是什么,尤其是方法返回的结果很重要。如果经过多组数据测试答案输出结果都正确,这样会大大地减少了读题、解题过程的时间,那这答案也差不多了是吧。
题目一定要看清楚了,我的建议是你在画板上边画边思考,完了千万不要漏了判定条件,最后是用例多测上几组,来验证自己是对的,这里呢我姐的可以用枚举子集的思想然后判断是否满足题意,注意基础题不要丢分了。
3编程题
敲代码之前先把所有题目和分数都大致过一遍,先选简单的再选分数很高但很有把握的写,再选难点题目,不按题号依次递进。
比较难的题目可以先在文本里写伪代码,把思路画在画板上搞清楚了边码边调试往往比上来直接撸代码来得高效。
如果知道题意写代码题,要判断时间复杂度和空间复杂度要不要超时,没得把握先别写,免得浪费时间。
有大量相同的代码块,不要犹豫直接CV。蓝桥杯考试时间虽然不短,但是题量很大。因此,时间的合理分配显得非常重要。
蓝桥杯答题的分数看的是你测试数据的通过率,所有务必把能过的都码上去,这里的意思如果想不出完美的AC方案的话,也可以先解决一小部分的数据规模,如果你实在不会这题,先暴力嘛,祈求一点点测试样例,反正比看空起好啦。
给你举个例子
JavaB组第10题要算乘积最大,好像你乍一看没什么好的想法,然后做到最后一题一般也没多少时间了嘛,为了抢分啊,不妨可以就想的简单点。这个题目无非就是给你一堆数字,数字能有什么呢,正负零。直接考虑全正或者全负的情况,这两种简单情况的代码写起来并不复杂吧?后台的测试样例里面不可能都是复杂情况的,一般测试样例也是有梯度的,从简单到难,从普遍情况到极端情况,所以即使你只写了针对简单情况的,你也能拿部分分数。再比如模拟赛第7题风险度量,一看这题心想“完了,我还没学过并查集”,那怎么办呢?注意看题目,有一句话叫“如果询问的两点不连通则输出-1”,这句话隐含意义就是后台至少有一组测试样例是不连通的。那与其空着不写,不如你就写个程序输出-1,假如后台有5组测试样例,你也拿到了1/5的分到手了吧。
这个比赛系统在你提交了代码之后是看不到结果的,所以不会告诉你是WA了还是有没有超时。通常题目提供的测试样例只有一两组,为了进一步验证自己代码的正确性,可以自己再找几组测试样例测试一下。
有同学想知道大概什么时候出省赛结果,我印象里结果出的挺快的,考后两三周的样子。
参考建议
可能有小伙伴担心校区不同,这个影响不大,记得我当时自己刚开始才加比赛的时候,我个人认为竞赛这种事,他是一个层次面上的比赛,虽然有少数上一层次和下一层次的人混在里面,但是大部分人还是水平相当的,不然比赛咋整你说是不是?而且由于蓝桥杯的坑点,提交之后你不知道自己的代码对错,还不能带算法模板这类纸质材料进去,所以就算有的同学编程比较拿手,也没有绝对的优势,当然很优秀的除外。做过真题的小伙伴也看得出来蓝桥杯的题目难度是有在逐年增加的,而且编程题的比例也在增加,我前面说做好填空题就行,但是现在有个别填空题也不那么好做,可是编程题也不会让你一个都做不了啊,所以再次总结一下就是,做好填空题,编程题竟可能多的拿分。说到真题的变化,还有一点想提的是,个人感觉蓝桥杯涉及的算法也在变多,省赛重基础算法,国赛重高级算法,虽然基础算法和高级算法这两个范围非常的广,但是有意统计一下里面出现的具体算法和频率,也可以知道基本上考的就那么几个,但是近年来也逐渐多了一些没有考过,我是说多了一些,不要紧张,还是占少数的,这里提这一点的原因是想让学有余力并且想拿大奖的同学,后期刷题的时候可以拓宽刷题的算法。
如何复习
1、初学编程的同学是这样的:
看到题目我有一点思路,但是我写不出来,去网上搜了题解,看了都能理解,可是我还是写不出来,这个问题我自己的学弟学妹们也问过我很多次,我自己当年开始时也是这样的。因为刚起步嘛,你此时的编程能力还不足以让你一个人来完成一道题,那不如就大大方方的借鉴别人的呗。先把你能想到的代码写下来,无论多少都先写下来,然后再去参考别人的代码继续写下去。如果看过之后忘记了或者自己卡住了,再回过头看一眼别人的,然后把自己的代码补全。千万不要自己死磕到底,或者完全抄别人的代码(就是屏幕一分为二,一边你的一边别人的,然后抄的得跟练打字似的)!当然也不能觉得这样做一遍,自己就都会了,信不信过几天你就忘了hhhhh 所以呢,过几天之后你还要回过头重复刷。起步的时候,刷题不在与题量多,而在于重复次数。刷个两三遍,差不多就能记牢了,这个时候你写的代码才完全是你的东西啦~
2、第一次参加的同学:
个人觉得蓝桥刚开始准备的时候,还是要先刷真题,了解了解情况。我在题解表格中也列出了每个题目涉及的算法,不难看出常考的算法有枚举(暴力)、递归、贪心、搜索(dfs和bfs)等基础算法,基础算法学起来也不难,多看看多做做就行了。如果时间有限,那么就只刷真题,多刷几遍。如果时间充足,那么刷完真题后,你也大致知道了蓝桥杯常考的算法和自己薄弱的算法,这个时候就可以去别的oj上练专题。
3、第二次参加的同学:
这就说的我,首先呢,不要觉得是第二次参加就希望大,这样真的真的很容易滑铁卢,好好准备还是需要的。可以先回顾一遍真题,省赛题不能满足你的话,也可以去刷国赛真题,或者去别的oj上刷题。由于是第二次参加,所以可以适当地让自己多学一些高级算法,当然基础算法也要巩固一下的,不能忘了本嘛~
4、第三次参加的同学:
你都是第三次参加了,是个成熟的选手啦,还要我给建议嘛?开玩笑的啦~ 一般第三次参加的同学都是大三生了,这个时候可能还要忙考研考公找工作之类的事情,所以准备时间可能并不是那么充裕,但是前两年的刷题经验应该也积累了不少了,不过就算没有太多时间,也有偶尔抽出一点时间做题,比如一天做个一两题这样的,状态和手感真的很重要!
🔑 二 如何混分篇
这种集中在结果填空与代码填空里面。这时你看能不能借助日历、计算器、WPS、txt文本、Notepad++或者数学方法等工具进行快速解出来,最后再选择用Eclipse代码暴力破解。
EXCEL用法
如果标题出现:第几天
2000年的1月1日,是那一年的第1天。
那么,2000年的5月4日,是那一年的第几天?
注意:需要提交的是一个整数,不要填写任何多余内容。
题解:
1、在EXCEL的两个格子上写上要的日期
2、点击C,在fx那里写上 =B1-A1
3、回车得答案,因为1/1是第一天,所以5/4是当年的第124+1 = 125天
4、而且还可以计算某天为星期几(省赛题目曾经出过)
计算器用法
标题:明码
汉字的字形存在于字库中,即便在今天,16点阵的字库也仍然使用广泛。
16点阵的字库把每个汉字看成是 16x16 个像素信息。并把这些信息记录在字节中。
一个字节可以存储8位信息,用32个字节就可以存一个汉字的字形了。
把每个字节转为2进制表示,1表示墨迹,0表示底色。每行2个字节,
一共16行,布局是这样的
第1字节,第2字节
第3字节,第4字节
....
第31字节, 第32字节
这题是给你一段多个汉字组成的信息,每个汉字用32个字节表示,这里给出了字节作为有符号整数的值。
题目的要求隐藏在这些信息中。你的任务是复原这些汉字的字形,从中看出题目的要求,并根据要求填写答案。
这段信息是(一共10个汉字):
4 0 4 0 4 0 4 32 -1 -16 4 32 4 32 4 32 4 32 4 32 8 32 8 32 16 34 16 34 32 30 -64 0
16 64 16 64 34 68 127 126 66 -124 67 4 66 4 66 -124 126 100 66 36 66 4 66 4 66 4 126 4 66 40 0 16
4 0 4 0 4 0 4 32 -1 -16 4 32 4 32 4 32 4 32 4 32 8 32 8 32 16 34 16 34 32 30 -64 0
0 -128 64 -128 48 -128 17 8 1 -4 2 8 8 80 16 64 32 64 -32 64 32 -96 32 -96 33 16 34 8 36 14 40 4
4 0 3 0 1 0 0 4 -1 -2 4 0 4 16 7 -8 4 16 4 16 4 16 8 16 8 16 16 16 32 -96 64 64
16 64 20 72 62 -4 73 32 5 16 1 0 63 -8 1 0 -1 -2 0 64 0 80 63 -8 8 64 4 64 1 64 0 -128
0 16 63 -8 1 0 1 0 1 0 1 4 -1 -2 1 0 1 0 1 0 1 0 1 0 1 0 1 0 5 0 2 0
2 0 2 0 7 -16 8 32 24 64 37 -128 2 -128 12 -128 113 -4 2 8 12 16 18 32 33 -64 1 0 14 0 112 0
1 0 1 0 1 0 9 32 9 16 17 12 17 4 33 16 65 16 1 32 1 64 0 -128 1 0 2 0 12 0 112 0
0 0 0 0 7 -16 24 24 48 12 56 12 0 56 0 -32 0 -64 0 -128 0 0 0 0 1 -128 3 -64 1 -128 0 0
注意:需要提交的是一个整数,不要填写任何多余内容。
题目大意是这样
上面一行数字的十进制转化为二进制,而且两个数字的二进制数为一行,最后一行数字组成的二进制数的1可以画成代表一个文字,一共10行,最后输出结果。
题解:
如果不会敲题目,这时候可以用计算器的十进制转二进制的方法。比如第一行为4 0两个数字,这时候用计算器算出
4的八个二进制为 00000010
0的八个二进制为 00000000
反正同一行变成一行
0000001000000000
2 如此类推可以得出第一个答案为,其中就是二进制的1空着的为二进制的0,这是我用程序输出第一个字的答案
3、最后的10个汉字是:九的九次方等于多少?
答案就输入:387420489
比赛注意事项
- 不要使用 package 语句
- 类的名称必须采用 Main 方式命名
- 提前设置好你常用代码模板
- 同时打开JDK1.6的API文档
Eclipse使用技巧
1,debug调试
F5: 跳入方法
F6: 向下逐行调试
F7:跳出方法
F8: 直接跳转到下一个端点
2,Ctrl+Q 跳回上一操作处
3,Ctrl+D 快速删除光标行
4,Ctrl+O 查看当前类的所有 方法
三 🏅 必需掌握的
1,输入:static Scannner sc = new Scanenr(System.in);
2、换行:sc.nextLine 整数sc.nextInt 小数sc.nextDouble
3、一维数组输出:java.util.Arrays.toString(A); (A为一维数组)
3、多维数组输出:java.util.Arrays.deepToString(B); (B为多维数组)
4、两数字交换: int temp=a1; a1=a2; a2=temp;
5、一维数组长度:int A[] = {
1,2,3,4,5} A.length=5
6、二维数组长度:int[][] A = new int[3][4] A.length=3 A[0].length=4
7、数组长度总结:A.length 表示有多少行 A[i].length表示第行列有多少列
7、break和continue:break结束整个循环体,continue结束单个循环
8、基本数据类型转大数:Bigdecimal c = Bigdecimal.value(X);
9、强制转换:long b = (long)a;
10、字符串问题:String类型定义的是字符串,char[]定义的是字符数组
11、String转化为char:char[] c1 = s1.toCharArrays(s1);
12、字符串分割:分割的字符串必须用字符串数组存储String[] str = s.split("/");
13、强制结束进程:system.exit(0);
14、int和Integer:自动装箱:Integer.valueOf(int i),自动拆箱:i.intValue()
15、对象类比较用equals,地址比较用==
16、定义integer类,-128~127存在缓存中,其他的需要创建一个新的Integer对象
17、定义数字变量,int比Integer快
18、定义当前时间:double startTime = System.currentTimeMillis();
19、声明boolean数组:Boolean Bool[] = new boolean[xx];
20、构造器:public 类名(){
} (构造方法没有返回值, 构造方法:一般用于给对象赋初始值)
21、this关键字:(1)指代当前对象(2)指代当前类(3)指代构造方法(只能放在首行)
22、求最大公约数和最小公倍数时需要求绝对值:Math.abs();
23、java输出换行:System.out.print("\n"+......);
java字符串和字符数组的转换
(1)String字符串转化为字符数组:String->char[] char[] a1 = s1.toCharArrays();
(2)char[]字符数组转化为字符串:char[]->String String[] s1 = String.valueOf(a1);
(2)char[]字符数组转化为字符串:char[]->String String s1 = new String(a1);
(3)String查找字符串中的一个字符:char a = String.charAt(index);
(3)String查找字符串中的一个字符:char a = String.codePointAt(index);
(4)String字符串转换成大写:String up = s1.toUppercase();
(5)String字符串转化为小写:String low = s1.toLowercase();
(6)char字符转化成大写:String upch = a1.toString().toLowercase();
(7)char字符转化成小写:String lowch = a1.toString().toUppercase();
(8)String字符串替换:String rep = s1replace(oldChar, newChar);
(9)String字符串字符char的第一次索引:int a = s1.indexOf(String str);
(10)String字符串字符char的最后一次索引:int a = s1.lastIndexOf();
(11)String字符串的子字符串:String sub = s1.substring(beginIndex);
(11)String字符串的子字符串:String sub = s1.substring(beginIndex,endIndex);
(12)String字符串删掉最后一个字符:s = s.subString(0,s.length-1);
(13)二维数组克隆:
(1)copy = c.clone(); //直接复制全部
(2)System.arraycopy(c,0,copy,0,N); //最底层,复制c到copy,从0-N
(3)copy = Arrays.copyOf(c,N); //复制c到copy,复制的长度为N
(4)copy = Arrays.copyOfRange(c,0,N);//复制c到copy,从c的第0到N个复制
效率:System.arraycopy > Arrays.copyOf > for循环 > clone
1 这里想强调下大数类的用法
BigInteger
类可以表示 long
型都无法表示的整型数据。大数类 BigInteger
不是基本数据类型,对于大数据的操作都是通过字符串来,因此不能用整型的"+"、"-"、"*"、"/" 来简单计算,他有自己运算方法。
使用大数类来操作数据前,需要先通过构造器创建一个BigInteger 对象。
BigInteger构造器
查看文档关于BigInteger的Java API
- valueOf
public static BigInteger valueOf(long val)
返回一个BigInteger, 其值等于指定 long 的值
BigInteger a = new BigInteger("666666666666666666666");
BigInteger b = BigInteger.valueOf(3);
得到大数类对象之后就可以进行运算。
2 关于大数类四则运算
- 大数加法
public BigInteger add(BigInteger val)
与整数的加法一样 不过返回值是BigInteger
a.add(b) //a加b
- 大数减法
public BigInteger subtract(BigInteger val)
与整数的减法一样 不过返回值是BigInteger
a.subtract(b) //a减b
- 大数乘法
public BigInteger multiply(BigInteger val)
与整数的乘法一样 不过返回值是BigInteger
a.multiply(b) //a乘以b
- 大数除法
public BigInteger divide(BigInteger val)
与整数除法一样 不过返回值是BigInteger
另外还要注意处理除数为零的异常
ArithmeticException - if val is zero
- 其他常用方法
public BigInteger pow(int exponent)
返回当前大整数的exponent次方
public BigInteger abs()
返回当前大整数的绝对值
public String toString()
将当前大整数转换成十进制的字符串形式
这里举例子
package 大数类常用方法;
import java.math.BigInteger;
/**
* @author JohnnyLin
* @version Creation Time:2020年6月12日 下午9:44:39
*/
public class BigInteger的常用方法 {
public static void main(String[] args) {
BigInteger a=new BigInteger("666666666666666666666");
BigInteger b=BigInteger.valueOf(3);
System.out.println(a.add(b)); //加法 666666666666666666669
System.out.println(a.subtract(b) );//减法 666666666666666666663
System.out.println(a.multiply(b));//乘法 1999999999999999999998
System.out.println(a.divide(b));//除法 222222222222222222222
System.out.println(b.pow(5)); //b的五次方 243
System.out.println(b.subtract(a).abs());//b-a的绝对值 666666666666666666663
String s=b.toString(); //将b转为字符串类型
System.out.println(s); //3
}
}
3 总结的小技巧
%.3f保留3位小数并四舍五入
&&的优先级要高与||和&&有点类似于*,||类似于+
if(1) if(b) x++; else
//else默认和最近的一个if配对
if(fabs(m*my-n*ny)<0.000001)
//浮点数判断相等,要近似判断,如果用==得不到结果。//fabs(float x)浮点数x的绝对值
质数:又叫素数,在大于1的自然数中,除了1和它本身以外不再有其他因数。
互质数:公因数只有1的两个非零自然数
同余定理,例如:1234%10
1234%10=(((1%10*10+2)%10*10+3)%10*10+4)%10
高次方数的尾数
规律:1-100中 凡是有因子5,尾数就增加一个零;有因子25,尾数就增加两个零。
100!有24个零,1000!有249个零。
int main() {
int i;
for(i=1; i<100; i++) {
if(i%2==0) //填空
printf("%d \n", i*i/2);
else
printf("%d \n", (i*i-1)/2);
}
printf("\n");
}
求数字下标规律:1,3,6,10, 公式:i*(i+1)/2
唯一分解定理:
ll getfac(ll x)//唯一分解定理
{
ll ans=1;
for(int i=1;i<=cnt&&primel[i]*primel[i]<=x;i++) {
ll sum=0;
while(x%primel[i]==0) {
sum++;
x/=primel[i];
}
ans*=(sum+1);
} if(x>1) ans*=2;
returnans;
}
一年的12个月:1-12月
31,28/29、31、30、31、30、31、31、30、31、30、31
闰年: (year%40&&year%100!=0)||(year%4000)
四 📖 常用代码模板
辗转相除法求最大公约数
int gcd(int a, intb) {
if (b == 0) return a;
else return gcd(b, a % b);
}
//最小公倍数
lcm(a,b)=(a*b)/gcd(a,b)
判断闰年
int is_leap_year(int year){
if(year%400==0||(year%100!=0&&year%4==0)){
return 1;
}
return 0;
暴力搜索:dfs。凑算式
#include<stdio.h>
int num[10];
int ans=0;
bool visit[10];
void solve(){
double sum = num[0]+(double)num[1]