蓝桥杯 2019年国赛真题(Java 大学C组)
#A 奇数倍数
#B 递增序列
#C 平方拆分
#D 切割
#E 序列求和
#F 最长子序列
#G 数正方形
#H 矩阵计数
#I 大胖子走迷宫
#J 估计人数
#A 奇数倍数
题目:
问题描述请你找到最小的整数 X 同时满足:
X 是 2019 的整倍数
X 的每一位数字都是奇数
代码:
import java.util.*;public class Main
{public static void main(String args[]){for (int i = 2019; i < 1000000; i+=2019) {int x=0;int t=i;while(t>0) {if (t%10%2==0) {x=1;}t=t/10;}if (x==0) {System.out.println(i);break;}}}
}
#B 递增序列
题目:
问题描述对于一个字母矩阵,我们称矩阵中的一个递增序列是指在矩阵中找到两个字母,它们在同一行,同一列,或者在同一 45 度的斜线上,这两个字母从左向右看、或者从上向下看是递增的。
例如,如下矩阵中
LANN
QIAO
有LN、LN、AN、AN、IO、AO、LQ、AI、NO、NO、AQ、IN、AN 等 13 个递增序列。注意当两个字母是从左下到右上排列时,从左向右看和从上向下看是不同的顺序。
对于下面的 30 行 50 列的矩阵,请问总共有多少个递增序列?(如果你把以下文字复制到文本文件中,请务必检查复制的内容是否与文档中的一致。在试题目录下有一个文件 inc.txt,内容与下面的文本相同)VLPWJVVNNZSWFGHSFRBCOIJTPYNEURPIGKQGPSXUGNELGRVZAG
SDLLOVGRTWEYZKKXNKIRWGZWXWRHKXFASATDWZAPZRNHTNNGQF
ZGUGXVQDQAEAHOQEADMWWXFBXECKAVIGPTKTTQFWSWPKRPSMGA
BDGMGYHAOPPRRHKYZCMFZEDELCALTBSWNTAODXYVHQNDASUFRL
YVYWQZUTEPFSFXLTZBMBQETXGXFUEBHGMJKBPNIHMYOELYZIKH
ZYZHSLTCGNANNXTUJGBYKUOJMGOGRDPKEUGVHNZJZHDUNRERBU
XFPTZKTPVQPJEMBHNTUBSMIYEGXNWQSBZMHMDRZZMJPZQTCWLR
ZNXOKBITTPSHEXWHZXFLWEMPZTBVNKNYSHCIQRIKQHFRAYWOPG
MHJKFYYBQSDPOVJICWWGGCOZSBGLSOXOFDAADZYEOBKDDTMQPA
VIDPIGELBYMEVQLASLQRUKMXSEWGHRSFVXOMHSJWWXHIBCGVIF
GWRFRFLHAMYWYZOIQODBIHHRIIMWJWJGYPFAHZZWJKRGOISUJC
EKQKKPNEYCBWOQHTYFHHQZRLFNDOVXTWASSQWXKBIVTKTUIASK
PEKNJFIVBKOZUEPPHIWLUBFUDWPIDRJKAZVJKPBRHCRMGNMFWW
CGZAXHXPDELTACGUWBXWNNZNDQYYCIQRJCULIEBQBLLMJEUSZP
RWHHQMBIJWTQPUFNAESPZHAQARNIDUCRYQAZMNVRVZUJOZUDGS
PFGAYBDEECHUXFUZIKAXYDFWJNSAOPJYWUIEJSCORRBVQHCHMR
JNVIPVEMQSHCCAXMWEFSYIGFPIXNIDXOTXTNBCHSHUZGKXFECL
YZBAIIOTWLREPZISBGJLQDALKZUKEQMKLDIPXJEPENEIPWFDLP
HBQKWJFLSEXVILKYPNSWUZLDCRTAYUUPEITQJEITZRQMMAQNLN
DQDJGOWMBFKAIGWEAJOISPFPLULIWVVALLIIHBGEZLGRHRCKGF
LXYPCVPNUKSWCCGXEYTEBAWRLWDWNHHNNNWQNIIBUCGUJYMRYW
CZDKISKUSBPFHVGSAVJBDMNPSDKFRXVVPLVAQUGVUJEXSZFGFQ
IYIJGISUANRAXTGQLAVFMQTICKQAHLEBGHAVOVVPEXIMLFWIYI
ZIIFSOPCMAWCBPKWZBUQPQLGSNIBFADUUJJHPAIUVVNWNWKDZB
HGTEEIISFGIUEUOWXVTPJDVACYQYFQUCXOXOSSMXLZDQESHXKP
FEBZHJAGIFGXSMRDKGONGELOALLSYDVILRWAPXXBPOOSWZNEAS
VJGMAOFLGYIFLJTEKDNIWHJAABCASFMAKIENSYIZZSLRSUIPCJ
BMQGMPDRCPGWKTPLOTAINXZAAJWCPUJHPOUYWNWHZAKCDMZDSR
RRARTVHZYYCEDXJQNQAINQVDJCZCZLCQWQQIKUYMYMOVMNCBVY
ABTCRRUXVGYLZILFLOFYVWFFBZNFWDZOADRDCLIRFKBFBHMAXX
代码:
package 蓝桥杯省模拟赛_高职组;import java.util.Scanner;public class 递增序列 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int[] num = new int[n];int temp=-1;int count=0;int max=0;for (int i=0;i<n;i++){num[i]=sc.nextInt();if(count==0){temp=num[i];count++;}if(temp<num[i]){temp=num[i];count++;}else{temp=num[i];max=Math.max(count,max);count=1;}}System.out.println(max);}
}
#C 平方拆分
题目:
问题描述将 2019 拆分为若干个两两不同的完全平方数之和,一共有多少种不同的方法?
注意交换顺序视为同一种方法,例如 13^2 + 25^2 + 35^2 = 2019 与 13^2 + 35^2 +25^2 = 2019 视为同一种方法(^代表平方)。
代码:
public class Main1 {public static void main(String[] args) {dfs(2019,0,45);System.out.println(sum);}static int sum;//深搜平方和为2019的所有子集private static void dfs(int num, int min, int max) {if (num < 0) {return;}if (num == 0) {sum ++;return;}for (int i = min; i < max; i++) {//去重,保证下一位数字一定大于当前数字dfs(num - i * i, i + 1, max);}}
}
#D 切割
题目:
问题描述在 4 × 4 的方格矩阵中画一条直线。则直线穿过的方格集合有多少种不同的可能?这个里直线穿过一个方格当且仅当直线将该方格分割成面积都大于 0 的两部分。答案提交这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
代码:
import java.util.HashSet;
import java.util.Set;public class Main {//方格字符标记String[][] ss = { { "1", "2", "3", "4" }, { "5", "6", "7", "8" }, { "9", "a", "b", "c" }, { "d", "e", "f", "g" } };//结果集合Set<String> set = new HashSet<String>();int a = 0, b = 0, c = 0, d = 0;public Main() {//遍历x1,x2for (int x1 = 0; x1 <= 400; x1++) {for (int x2 = 0; x2 <= 400; x2++) {// System.out.println("x1="+x1+",x2="+x2);if (x1 == 0 || x1 == 400) {// 固定x1,直线从侧边出去的结果getlist4(x1, x2);}// 固定y=400,直线从顶部出去的数量结果getlist(x1, x2);}}System.out.println(a);System.out.println(b);System.out.println(c);System.out.println(d);System.out.println(set.size());}// 分别统计字符开头的数据,用于观察public void count(String s) {if (s.startsWith("1")) {a++;} else if (s.startsWith("2")) {b++;} else if (s.startsWith("3")) {c++;} else if (s.startsWith("4")) {d++;}}// 求顶部结果public void getlist(double x1, double x2) {String s = "";for (int i = 0; i < 400; i++) {double x = x2 + (x1 - x2) / 400 * i;if (x > 0 && x < 100) {// 第一格内if (s.equals("") || !s.substring(s.length() - 1, s.length()).equals(ss[i / 100][0])) {s += ss[i / 100][0];}} else if (x > 100 && x < 200) {// 第二格内if (s.equals("") || !s.substring(s.length() - 1, s.length()).equals(ss[i / 100][1])) {s += ss[i / 100][1];}} else if (x > 200 && x < 300) {// 第三格内if (s.equals("") || !s.substring(s.length() - 1, s.length()).equals(ss[i / 100][2])) {s += ss[i / 100][2];}} else if (x > 300 && x < 400) {// 第四格内if (s.equals("") || !s.substring(s.length() - 1, s.length()).equals(ss[i / 100][3])) {s += ss[i / 100][3];}}}// 存起来if (!s.equals("") && !set.contains(s)) {// System.out.println(s);count(s);set.add(s);}}// 求两侧边结果public void getlist4(double x1, double x2) {String s = "";// 这里x1,x2固定时,y在变化,for (int j = 0; j < 400; j++) {//每次变化都是不一样的直线for (int i = 0; i < j; i++) {double x = x2 + (x1 - x2) / j * i;if (x > 0 && x < 100) {// 第一格内if (s.equals("") || !s.substring(s.length() - 1, s.length()).equals(ss[i / 100][0])) {s += ss[i / 100][0];}} else if (x > 100 && x < 200) {// 第二格内if (s.equals("") || !s.substring(s.length() - 1, s.length()).equals(ss[i / 100][1])) {s += ss[i / 100][1];}} else if (x > 200 && x < 300) {// 第三格内if (s.equals("") || !s.substring(s.length() - 1, s.length()).equals(ss[i / 100][2])) {s += ss[i / 100][2];}} else if (x > 300 && x < 400) {// 第四格内if (s.equals("") || !s.substring(s.length() - 1, s.length()).equals(ss[i / 100][3])) {s += ss[i / 100][3];}}}// 存起来if (!s.equals("") && !set.contains(s)) {// System.out.println(s);count(s);set.add(s);}s = "";}}public static void main(String[] args) {new Main();}}
#E 序列求和
题目:
学习了约数后,小明对于约数很好奇,他发现,给定一个正整数 t,总是可以找到含有 t 个约数的整数。小明对于含有 t 个约数的最小数非常感兴趣,并把它定义为 St 。
例如 S1 = 1, S2 = 2, S3 = 4, S4 = 6,· · · 。
现在小明想知道,前 60 个 Si 的和是多少?即 S1 + S2 + · · · + S60 是多少?答案提交这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
代码:
package com.cxyax.november.tenth;import java.util.ArrayList;
import java.util.List;public class Main {public static void main(String[] args) {//用list集合去装每次的值List list = new ArrayList();int sum = 0;//遍历循环60次,即S60for(int i = 1; i <= 60;i++) {//每次都进行爆破for(int j = 1; ; j++ ) {//在每次进入时清除list集合,下步使用list.clear();//寻找约数for(int k = 1; k <= j;k++) {//判断约数if(j%k==0) {//如果是把约数加进list集合list.add(k);}//判断因数个数是否等于iif(list.size() == i) {sum += j;break;}}//如果等于i即跳出循环if(list.size() == i) {break;}}}System.out.println(sum);}
}
#F 最长子序列
题目:
问题描述我们称一个字符串 S 包含字符串 T 是指 T 是 S 的一个子序列,即可以从字符串 S 中抽出若干个字符,它们按原来的顺序组合成一个新的字符串与 T 完全一样。
给定两个字符串 S 和 T,请问 T 中从第一个字符开始最长连续多少个字符被 S 包含?输入格式输入两行,每行一个字符串。第一行的字符串为 S,第二行的字符串为 T。
两个字符串均非空而且只包含大写英文字母。输出格式输出一个整数,表示答案。
测试样例1
Input:
ABCDEABCD
AABZOutput:
3
评测用例规模与约定对于 20% 的评测用例,1 ≤ |T| ≤ |S | ≤ 20;
对于 40% 的评测用例,1 ≤ |T| ≤ |S | ≤ 100;
对于所有评测用例,1 ≤ |T| ≤ |S | ≤ 1000。
代码:
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sn=new Scanner(System.in);String S=sn.next();String T=sn.next();char[] s=S.toCharArray();char[] t=T.toCharArray();int k=0;//统计个数for(int j=0;j<s.length;j++) {if(t[k]==s[j])k++;}System.out.println(k);}
}
#G 数正方形
题目:
问题描述在一个 N × N 的点阵上,取其中 4 个点恰好组成一个正方形的 4 个顶点,一共有多少种不同的取法?
由于结果可能非常大,你只需要输出模 109 + 7 的余数。
(如:图7)所示的正方形都是合法的。输入格式输入包含一个整数 N。输出格式输出一个整数代表答案。测试样例1
Input:
4Output:
20
评测用例规模与约定对于所有评测用例,2 ≤ N ≤ 1000000。
代码:
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sn = new Scanner(System.in);int n = sn.nextInt() - 1;long count = 0;long num = 1000000007;//平放// a 表示正方形边长for (int a = 1; a <= n; a++) {count += (n - a + 1) * (n - a + 1);count%=num;}// 斜放//i+j=斜正方形所占区域的边长=平放正方形的边长//但i+j>=2,也就是平放正方形的边长从2开始for (int i = 1; i <= n - 1; i++) {for (int j = 1; j <= n - i; j++) {count += (n - (i + j) + 1) * (n - (i + j) + 1);count%=num;}}System.out.println(count);}
}
#H 矩阵计数
题目:
问题描述一个 N × M 的方格矩阵,每一个方格中包含一个字符 O 或者字符 X。
要求矩阵中不存在连续一行 3 个 X 或者连续一列 3 个 X。
问这样的矩阵一共有多少种?输入格式输入一行包含两个整数 N 和 M。输出格式输出一个整数代表答案。测试样例1
Input:
2 3Output:
49
评测用例规模与约定对于所有评测用例,1 ≤ N, M ≤ 5。
代码:
import java.util.Scanner;public class test1 {public static void main(String[] args) {Scanner sc=new Scanner(System.in);int n1=sc.nextInt();int n2=sc.nextInt();long starttime=System.currentTimeMillis();int a [][]=new int[n1][n2];int sum=0;for(int t=0;t<Math.pow(2, n1*n2);t++) {int x=0;//将数组赋值for(int i=0;i<n1;i++) {for(int j=0;j<n2;j++) {if((t>>x&1)==1) {a[i][j]=1;}x++;}}//检查数组if(check(a)) {}else {sum++;}//查看数组
// System.out.println(t);
// for(int i=0;i<n1;i++) {
// for(int j=0;j<n2;j++) {
// System.out.print(a[i][j]+" ");
//
// }
// System.out.println();
// }
// System.out.println("---------------------");//数组清空for(int i=0;i<n1;i++) {for(int j=0;j<n2;j++) {a[i][j]=0;}}}System.out.println(sum);long endtime=System.currentTimeMillis(); System.out.println("所用时间:"+(endtime-starttime));}private static boolean check(int[][] a) {int x=0;for(int i=0;i<a.length;i++) {for(int j=0;j<a[0].length;j++) {if(a.length-i>2&a[i][j]==1) {if(a[i+1][j]==1&a[i+2][j]==1) {x=1;return true;}}if(a[0].length-j>2&a[i][j]==1) {if(a[i][j+1]==1&a[i][j+2]==1) {x=1;return true;}}}}if(x==1) {return true;}return false;
}
}
#I 大胖子走迷宫
题目:
问题描述小明是个大胖子,或者说是个大大胖子,如果说正常人占用 1 × 1 的面积,小明要占用 5 × 5 的面积。由于小明太胖了,所以他行动起来很不方便。当玩一些游戏时,小明相比小伙伴就吃亏很多。
小明的朋友们制定了一个计划,帮助小明减肥。计划的主要内容是带小明玩一些游戏,让小明在游戏中运动消耗脂肪。走迷宫是计划中的重要环节。
朋友们设计了一个迷宫,迷宫可以看成是一个由 n × n 个方阵组成的方阵,正常人每次占用方阵中 1 × 1 的区域,而小明要占用 5 × 5 的区域。小明的位置定义为小明最正中的一个方格。迷宫四周都有障碍物。
为了方便小明,朋友们把迷宫的起点设置在了第 3 行第 3 列,终点设置在了第 n-2 行第 n-2 列。
小明在时刻 0 出发,每单位时间可以向当前位置的上、下、左、右移动单位 1 的距离,也可以停留在原地不动。小明走迷宫走得很辛苦,如果他在迷宫里面待的时间很长,则由于消耗了很多脂肪,他会在时刻 k 变成一个胖子,只占用 3 × 3 的区域。如果待的时间更长,他会在时刻 2k 变成一个正常人,只占用 1 × 1 的区域。注意,当小明变瘦时迷宫的起点和终点不变。
请问,小明最少多长时间能走到迷宫的终点。注意,小明走到终点时可能变瘦了也可能没有变瘦。输入格式输入的第一行包含两个整数 n, k。
接下来 n 行,每行一个由 n 个字符组成的字符串,字符为 + 表示为空地,
字符为 * 表示为阻碍物。输出格式输出一个整数,表示答案。测试样例1
Input:
9 5
+++++++++
+++++++++
+++++++++
+++++++++
+++++++++
***+*****
+++++++++
+++++++++
+++++++++Output:
16
评测用例规模与约定对于 30% 的评测用例,1 ≤ n ≤ 50。
对于 60% 的评测用例,1 ≤ n ≤ 100。
对于所有评测用例,1 ≤ n ≤ 300,1 ≤ k ≤ 1000。
代码:
import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;public class Main {int n;//n行n列int k;//每k个小时小明瘦一圈char[][] maze;//迷宫地图boolean[][] vis;//地图访问标记ArrayBlockingQueue<Point> queue;//队列//位置节点class Point {int x;//横坐标int y;//纵坐标int time;//时间Point parent;//从哪个位置节点来的int a;//将肥胖转换成比常人的厚度,最开始为2,方便计算坐标public Point(int x1, int y1, Point p,int t,int a1) {this.x = x1;this.y = y1;this.parent = p;this.time=t;this.a=a1;}}public Main() {Scanner sn = new Scanner(System.in);n = sn.nextInt();k = sn.nextInt();maze = new char[n][n];vis = new boolean[n][n];sn.nextLine();queue = new ArrayBlockingQueue<Point>(n * n);for (int i = 0; i < n; i++) {maze[i] = sn.nextLine().trim().toCharArray();}//以上都是初始化queue.add(new Point(2, 2, null,0,2));//加入初始点vis[2][2] = true;//标记Point p=bfs();//获取到达终点的那个节点System.out.println(p.time);//输出时间
// //展示逆推路线
// while (p.parent != null) {
// System.out.println("x="+p.x+",y="+p.y+",time="+p.time+",a="+p.a);
// p = p.parent;
// }
// System.out.println("x="+p.x+",y="+p.y+",time="+p.time+",a="+p.a);}//广度优先搜索public Point bfs() {while (!queue.isEmpty()) {Point p = queue.poll();//取出队头//更新时间,胖瘦p.time++;if (p.time % k == 0 && p.a > 0)p.a--;//判断这个节点是不是已经是终点了if (p.x == n - 3 && p.y == n - 3)return p;//将四个方向可以移动的位置加入队列// 下if (check(p.x, p.y + 1,p) && !vis[p.y + 1][p.x]) {queue.add(new Point(p.x, p.y + 1, p,p.time,p.a));vis[p.y + 1][p.x] = true;}// 右if (check(p.x + 1, p.y,p) && !vis[p.y][p.x + 1]) {queue.add(new Point(p.x + 1, p.y, p,p.time,p.a));vis[p.y][p.x + 1] = true;}// 左if (check(p.x - 1, p.y,p) && !vis[p.y][p.x - 1]) {queue.add(new Point(p.x - 1, p.y, p,p.time,p.a));vis[p.y][p.x - 1] = true;}// 上if (check(p.x, p.y - 1,p) && !vis[p.y - 1][p.x]) {queue.add(new Point(p.x, p.y - 1, p,p.time,p.a));vis[p.y - 1][p.x] = true;}//如果存在空地但又无法移动,说明小明太胖了,重新加入队列,相当于等待if(exist(p.x, p.y)) {queue.add(p);}}//到不了终点,返回空return null;}// 判断p是否能移动到(x,y)public boolean check(int x, int y,Point p) {//x是否越界if (x - p.a >= 0 && x + p.a < n) {//y是否越界if (y - p.a >= 0 && y + p.a < n) {//x,y都正常,因此检查若移动后自身范围是否存在障碍物,若存在则无法移动for (int i = x - p.a; i <= x + p.a; i++) {for (int j = y - p.a; j <= y + p.a; j++) {if (maze[j][i] == '*')return false;}}//全部通过检查,可以移动return true;}}//未通过检查return false;}//检查上下左右当前还有空位public boolean exist(int x, int y) {//左if (x - 1 >= 0) {if (!vis[x - 1][y]) {return true;}}//上if (y - 1 >= 0) {if (!vis[x][y - 1]) {return true;}}//下if (y + 1 < n) {if (!vis[x][y + 1]) {return true;}}//右if (x + 1 < n) {if (!vis[x + 1][y]) {return true;}}return false;}public static void main(String[] args) {new Main();}
}
#J 估计人数
题目:
问题描述给定一个 N × M 的方格矩阵,矩阵中每个方格标记 0 或者 1 代表这个方格是不是有人踩过。
已知一个人可能从任意方格开始,之后每一步只能向右或者向下走一格。
走了若干步之后,这个人可以离开矩阵。这个人经过的方格都会被标记为 1,包括开始和结束的方格。注意开始和结束的方格不需要一定在矩阵边缘。
请你计算至少有多少人在矩阵上走过。输入格式输入第一行包含两个整数 N、M。
以下 N 行每行包含 M 个整数 (0/1),代表方格矩阵。输出格式输出一个整数代表答案。测试样例1
Input:
5 5
00100
11111
00100
11111
00100Output:
3
评测用例规模与约定对于所有评测用例,1 ≤ N, M ≤ 20,标记为 1 的方格不超过 200 个。
代码:
package 第十届决赛;import java.util.Arrays;
import java.util.Scanner;public class 估计人数 {static int[][] map;//地图static boolean[][] con;//关系图static int[] boy;//匹配点static boolean[] vis;static int n;static int m;static int sum = 1;public static void main(String[] args) {Scanner sc = new Scanner(System.in);n = sc.nextInt();m = sc.nextInt();map = new int[n][n];//写入图for (int i = 0; i < n; i++) {String str = sc.next();for (int j = 0; j < m; j++) {if (str.charAt(j) == '1')map[i][j] = sum++;}}con=new boolean[sum][sum];boy=new int[sum];vis=new boolean[sum];//初始化关系图for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (map[i][j]>0&&i+1<n&&map[i+1][j]>0) con[map[i][j]][map[i+1][j]]=true; if (map[i][j]>0&&j+1<m&&map[i][j+1]>0) con[map[i][j]][map[i][j+1]]=true;}}//Floydfor (int i = 1; i < sum; i++) {for (int j = 1; j < sum; j++) {for (int k = 1; k < sum; k++) {if(con[j][i]&&con[i][k]&&j!=k)con[j][k]=true;}}}//匈牙利算法int num=0;for (int i = 1; i < sum; i++) {Arrays.fill(vis, true);if(dfs(i)) num++;}System.out.println(sum-num-1);}static boolean dfs(int x) {for (int i = 1; i < sum; i++) {if(con[x][i]&&vis[i]) {vis[i]=false;if(boy[i]==0||dfs(boy[i])) {boy[i]=x;return true;}}}return false;}
}
上边是国赛决赛题,前几个是我自己的思路,后边几个实在是太难了,我从网上找的各路大佬的方法和思路贴过来的,大家可以找找思路做题。