试题 A: 递增序列(5分)

对于一个字母矩阵,我们称矩阵中的一个递增序列是指在矩阵中找到两个字母,它们在同一行,同一列,或者在同一 45 度的斜线上,这两个字母从左向右看、或者从上向下看是递增的。

例如,如下矩阵中

LANN
QIAO

有LN、LN、AN、AN、IO、AO、LQ、AI、NO、NO、AQ、IN、AN 等 13 个递增序列。注意当两个字母是从左下到右上排列时,从左向右看和从上向下看是不同的顺序。

对于下面的 30 行 50 列的矩阵,请问总共有多少个递增序列?

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
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

答案提交

52800

分析

读不懂题,所以干脆把八个方向都遍历一下。
例如当前字符位于c[i][j] 那么遍历每个字符的同时,满足c[x][y] > c[i][j] 且 x > i 或 y > j (两个字母从左向右看、或者从上向下看是递增)即可

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
public class Main {
static int[][] move = new int[][]{{1, 0}, {0, 1}, {-1, 0}, {0, -1}, {1, 1}, {-1, -1}, {1, -1}, {-1, 1}};
static int res = 0;

public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
char[][] c = new char[60][60];
for (int i = 1; i <= 30; i++) {
String str = scan.next();
for (int j = 1; j <= 50; j++) {
c[i][j] = str.charAt(j - 1);
}
}

for (int i = 1; i <= 30; i++) {
for (int j = 1; j <= 50; j++) {
char tmp = c[i][j];
for (int[] ints : move) {
for (int x = i + ints[0], y = j + ints[1]; x >= 1 && x <= 30 && y >= 1 && y <= 50; x += ints[0], y += ints[1])
if (c[x][y] > tmp && (x > i || y > j))
res++;
}
}
}
System.out.println(res);
}
}

试题 B: 平方拆分(5分)

将 2019 拆分为若干个两两不同的完全平方数之和,一共有多少种不同的方法?

注意交换顺序视为同一种方法,例如 132 + 252 + 352 = 2019 与 132 + 352 +252 = 2019 视为同一种方法。

答案提交

分析

跟回溯那篇文章的“组合总和”那道题有点像

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。

那么对于这道题,target 就是2019,又45 × 45 =2 025 > 2019,所以“无重复元素”的整数数组就是从0~45. 剩下的约束条件与本题也一致。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Main {
static LinkedList<List<Integer>> res = new LinkedList<>();
static LinkedList<Integer> path = new LinkedList<>();

public static void main(String[] args) {
backTrack(0, 2019);
System.out.println(res.size());
}

static void backTrack(int start, int target) {
if (target < 0) return;
if (target == 0) {
res.add(new ArrayList<>(path));
return;
}
for (int i = start; i < 45; i++) {
path.add(i);
backTrack(i + 1, target - i * i);
path.removeLast();
}
}
}

如果按照“组合总和”那道题写,那么代码就是上面这个样子的,有很多冗余的信息,我们并不需要返回具体的方案,而是只要一个方案数,所以我们可以把代码改写成下面这样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Main {
static int res = 0;

public static void main(String[] args) {
backTrack(0, 2019);
System.out.println(res);
}

static void backTrack(int start, int target) {
if (target < 0) return;
if (target == 0) {
res++;
return;
}
for (int i = start; i < 45; i++)
backTrack(i + 1, target - i * i);
}
}

试题 C: 切割(10分)

在 4 × 4 的方格矩阵中画一条直线。则直线穿过的方格集合有多少种不同的可能?

这个里直线穿过一个方格当且仅当直线将该方格分割成面积都大于 0 的两
部分。

答案提交

分析

Code

1

试题 D: 最优旅行(10分)

中国的高铁四通八达,乘坐方便,小明经常乘坐高铁在城市间旅游。

现在,小明又有了一个长假,他打算继续乘坐高铁旅游。这次,他打算到下面的城市旅游。

上海、广州、长沙、西安、杭州、济南、成都、南京、昆明、郑州、天津、太原、武汉、重庆、南昌、长春、沈阳、贵阳、福州。

小明打算从北京出发,游览以上每个城市正好一次,最终回到北京。在每个城市(除北京外),小明都至少停留 24 小时。而当小明决定从一个城市去往另一个城市时,他只会选择有直接高铁连接的城市,不会在中途换乘转车。

在试题目录下有一个文件 trip.txt 保存了小明可以选择的车次,小明不会
选择其他车次。

小明出发的时间是第 1 天的中午 12:00。请问,小明游览完以上城市正好一次,最终回到北京,最快需要多少分钟(请注意单位为分钟,请注意除北京外的城市需要至少停留 24 小时,即最少停留 1440 分钟)。

答案提交

分析

Code

1

试题 E: 序列求和(15分)

学习了约数后,小明对于约数很好奇,他发现,给定一个正整数 t,总是可以找到含有 t 个约数的整数。小明对于含有 t 个约数的最小数非常感兴趣,并把它定义为 S t。

例如 S 1 = 1, S 2 = 2, S 3 = 4, S 4 = 6,· · · 。

现在小明想知道,前 60 个 S i 的和是多少?即 S 1 + S 2 + · · · + S 60 是多少?

分析

Code

1