试题A:美丽的2(5分)
问题描述
小蓝特别喜欢 2,今年是公元 2020 年,他特别高兴。他很好奇,在公元 1 年到公元 2020 年(包含)中,有多少个年份的数位中包含数字 2?
分析
签到题,没什么好说的
答案:563
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Main { public static void main (String[] args) { int sum = 0 ; for (int i = 1 ; i <= 2020 ; i++) { for (char c : (i + "" ).toCharArray()) { if (c == '2' ) { sum++; break ; } } } System.out.println(sum); } }
试题B:扩散(5分)
问题描述
小蓝在一张无限大的特殊画布上作画。
这张画布可以看成一个方格图,每个格子可以用一个二维的整数坐标表示。小蓝在画布上首先点了一下几个点:(0, 0), (2020, 11), (11, 14), (2000, 2000)。只有这几个格子上有黑色,其它位置都是白色的。每过一分钟,黑色就会扩散一点。具体的,如果一个格子里面是黑色,它就会扩散到上、下、左、右四个相邻的格子中,使得这四个格子也变成黑色(如果原来就是黑色,则还是黑色)。
请问,经过 2020 分钟后,画布上有多少个格子是黑色的。
分析
BFS
画布是无限大,(0, 0)这个点会扩散到负坐标,所以我们干脆把所有坐标加上3000,拿一个8000×8000的数组来装
代码跟之前写的二叉树的层序遍历的模板有点像,层序遍历是遍历当层节点时,将该节点的子节点,加入到队列中
这道题可以抽象成一个四叉树,遍历完每个点的时候,将其周围的四个点加入队列中(需要判断一下周围四个点是否已经有黑点了,把不是黑点的添加到队列就行了)。
附上那篇文章的连接
答案:20312088
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public class Main { static int [][] move = new int [][]{{1 , 0 }, {-1 , 0 }, {0 , 1 }, {0 , -1 }}; static boolean [][] isBlack = new boolean [8000 ][8000 ]; static int res = 4 ; public static void main (String[] args) { LinkedList<Point> queue = new LinkedList <>(); queue.add(new Point (3000 , 3000 , 0 )); queue.add(new Point (5020 , 3011 , 0 )); queue.add(new Point (3011 , 3014 , 0 )); queue.add(new Point (5000 , 5000 , 0 )); isBlack[3000 ][3000 ] = true ; isBlack[5020 ][3011 ] = true ; isBlack[3011 ][3014 ] = true ; isBlack[5000 ][5000 ] = true ; while (!queue.isEmpty()) { Point p = queue.poll(); if (p.time == 2020 ) break ; isBlack[p.x][p.y] = true ; for (int i = 0 ; i < move.length; i++) { int x = p.x + move[i][0 ]; int y = p.y + move[i][1 ]; if (!isBlack[x][y]) { queue.add(new Point (x, y, p.time + 1 )); isBlack[x][y] = true ; res++; } } } System.out.println(res); } } class Point { int x; int y; int time; public Point (int x, int y, int time) { this .x = x; this .y = y; this .time = time; } }
试题C:阶乘约数(10分)
问题描述
定义阶乘 n! = 1 × 2 × 3 × · · · × n。
请问 100! (100 的阶乘)有多少个约数。
分析
100的阶乘,肯定是要用到BigInteger的,主要考察的是算数基本定理,数论里的东西,给定一个数n,求n的因子个数
下面是算数基本定理的模板,我们把它改写成BigInteger的就行
1 2 3 4 5 6 7 8 9 10 11 12 13 static int factors (long n) { int res = 1 , now; for (int i = 2 ; i * i <= n; i++) { now = 1 ; while (n % i == 0 ) { n /= i; now++; } if (now > 1 ) res *= now; } return n > 1 ? res *2 : res; }
答案: 39001250856960000
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class Main { public static void main (String[] args) { BigInteger s = BigInteger.ONE; for (int i = 1 ; i <= 100 ; i++) { s = s.multiply(new BigInteger (i + "" )); } System.out.println(getNum(s)); } static BigInteger getNum (BigInteger s) { BigInteger res = BigInteger.valueOf(1 ), now; for (BigInteger i = BigInteger.valueOf(2 ); i.multiply(i).compareTo(s) <= 0 ; i = i.add(BigInteger.valueOf(1 ))) { now = BigInteger.valueOf(1 ); while (s.mod(i).compareTo(BigInteger.ZERO) == 0 ) { s = s.divide(i); now = now.add(BigInteger.valueOf(1 )); } if (now.compareTo(BigInteger.valueOf(1 )) > 0 ) res = res.multiply(now); } return s.compareTo(BigInteger.valueOf(1 )) > 0 ? res.multiply(BigInteger.valueOf(2 )) : res; } }
试题D:本质上升序列(10分)
问题描述
小蓝特别喜欢单调递增的事物。
在一个字符串中,如果取出若干个字符,将这些字符按照在字符串中的顺序排列后是单调递增的,则成为这个字符串中的一个单调递增子序列。例如,在字符串 lanqiao 中,如果取出字符 n 和 q,则 nq 组成一个单调递增子序列。类似的单调递增子序列还有 lnq、i、ano 等等。小蓝发现,有些子序列虽然位置不同,但是字符序列是一样的,例如取第二个字符和最后一个字符可以取到 ao,取最后两个字符也可以取到 ao。小蓝认为他们并没有本质不同。
对于一个字符串,小蓝想知道,本质不同的递增子序列有多少个?
例如,对于字符串 lanqiao,本质不同的递增子序列有 21 个。它们分别是 l、a、n、q、i、o、ln、an、lq、aq、nq、ai、lo、ao、no、io、lnq、anq、lno、ano、aio。
请问对于以下字符串(共 200 个小写英文字母,分四行显示):(如果你把以下文字复制到文本文件中,请务必检查复制的内容是否与文档中的一致。在试题目录下有一个文件 inc.txt,内容与下面的文本相同)
tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhf
iadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqij
gihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmad
vrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl
本质不同的递增子序列有多少个?
分析
线性DP
dp[i]表示以s[i]结尾的本质不同的上升序列个数,而dp[i]与s[j] (0<j<i-1) 有关
如果s[i] > s[j],那么dp[i] = dp[i] + dp[j],这个应该很好理解
dp[j]是以s[j]结尾的上升序列个数,而s[i] > s[j],那么dp[i]就是自身加上dp[j]
dp[i]是以s[i]结尾的本质不同的递增子序列数量,如果s[i] == s[j],说明有相同字符结尾的序列,那dp[i]中必然包含了dp[j]中的所有序列,所以要减去dp[j]中重复的序列
举个例子 1 2 7 8 3 7
dp[i]
dp的值
对应的元素
dp[0]
1
1
dp[1]
2
2 12
dp[2]
4
7 17 27 127
dp[3]
8
8 18 28 78 128 178 278 1278
dp[4]
4
13 23 123
dp[5]
4
7 17 27 127 137 127 1237 37
s[2] == s[5] 均为7,可以看出dp[5]中包含了dp[2]中的所有内容,故要减去之后才是正解
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import java.util.*;public class Main { public static void main (String[] args) { char [] s = ("tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhf" + "iadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqij" + "gihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmad" + "vrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl" ).toCharArray(); int [] dp = new int [s.length]; Arrays.fill(dp, 1 ); for (int i = 0 ; i < s.length; i++) { for (int j = 0 ; j < i; j++) { if (s[i] > s[j]) dp[i] += dp[j]; if (s[i] == s[j]) dp[i] -= dp[j]; } } System.out.println(Arrays.stream(dp).sum()); } }
试题E:玩具蛇(15分)
题目:
问题描述
小蓝有一条玩具蛇,一共有 16 节,上面标着数字 1 至 16。每一节都是一个正方形的形状。相邻的两节可以成直线或者成 90 度角。小蓝还有一个 4 × 4 的方格盒子,用于存放玩具蛇,盒子的方格上依次标着字母 A 到 P 共 16 个字母。小蓝可以折叠自己的玩具蛇放到盒子里面。他发现,有很多种方案可以将玩具蛇放进去。
下图给出了两种方案:
分析
回溯,依次将每一个格子当初起点。
创建一个used数组,记录每个格子是否用过
创建一个move数组,用来遍历上下左右四个方向
创建一个res变量,用来储存方案数
回溯条件,当前玩具蛇长度为16,同时res++;
答案: 552
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class Main { static boolean [][] used = new boolean [5 ][5 ]; static int res = 0 ; static int [][] move = new int [][]{{1 , 0 }, {-1 , 0 }, {0 , 1 }, {0 , -1 }}; public static void main (String[] args) { for (int i = 1 ; i <= 4 ; i++) { for (int j = 1 ; j <= 4 ; j++) { used[i][j] = true ; backTrack(i, j, 1 ); used[i][j] = false ; } } System.out.println(res); } static void backTrack (int x, int y, int length) { if (length == 16 ) { res++; return ; } for (int i = 0 ; i < move.length; i++) { int x1 = x + move[i][0 ]; int y1 = y + move[i][1 ]; if (x1 <= 4 && x1 >= 1 && y1 <= 4 && y1 >= 1 && !used[x1][y1]) { used[x1][y1] = true ; backTrack(x1, y1, length + 1 ); used[x1][y1] = false ; } } } }
试题F:蓝肽子序列(15分)
分析
最长公共子序列问题
力扣:https://leetcode.cn/problems/qJnOS7/
只需要将给出的字符串,按照大写字母,拆成一个一个单词,就可以转化为上面的问题。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import java.util.*;public class Main { public static void main (String[] args) { Scanner scan = new Scanner (System.in); String s1 = scan.next(); ArrayList<String> strs1 = new ArrayList <>(); int tmp = 0 ; for (int i = 1 ; i < s1.length(); i++) { char c = s1.charAt(i); if (c >= 'A' && c <= 'Z' ) { strs1.add(s1.substring(tmp, i)); tmp = i; } } strs1.add(s1.substring(tmp)); String s2 = scan.next(); ArrayList<String> strs2 = new ArrayList <>(); int tmp2 = 0 ; for (int i = 1 ; i < s2.length(); i++) { char c = s2.charAt(i); if (c >= 'A' && c <= 'Z' ) { strs2.add(s2.substring(tmp2, i)); tmp2 = i; } } strs2.add(s2.substring(tmp2)); int [][] dp = new int [strs1.size() + 1 ][strs2.size() + 1 ]; for (int i = 1 ; i <= strs1.size(); i++) { for (int j = 1 ; j <= strs2.size(); j++) { if (strs1.get(i - 1 ).equals(strs2.get(j - 1 ))) dp[i][j] = 1 + dp[i - 1 ][j - 1 ]; else dp[i][j] = Math.max(dp[i - 1 ][j], dp[i][j - 1 ]); } } System.out.println(dp[strs1.size()][strs2.size()]); } }
试题G:皮亚诺曲线距离(20分)
分析
Code
试题H:画廊(20分)
分析
Code
试题I:补给(25分)
分析
Code
试题J:质数行者(25分)
问题描述
分析
Code