【春招笔试】2025.05.17淘天机考真题改编题
✅ 春招备战指南 ✅
💡 学习建议:
- 先尝试独立解题(建议用时:90分钟/套)
- 对照解析查漏补缺
🧸 题面描述背景等均已深度改编,做法和题目本质基本保持一致。
🍹 感谢各位朋友们的订阅,你们的支持是我们创作的最大动力
🌸 目前本专栏已经上线80+套真题改编解析,后续会持续更新的
春秋招合集 -> 互联网必备刷题宝典🔗
题目一:魔法棋盘构造
1️⃣:构造第一行为自然顺序排列
2️⃣:第二行为循环右移一位的排列,利用相邻整数互质的性质
难度:中等
这道题目的关键在于理解互质性质,并发现使用相邻数互质的规律可以简单构造。通过设计第一行为顺序排列,第二行为循环右移的排列,可以保证相邻格子的数字互质,从而构造出符合条件的魔法棋盘。
题目二:音律旋律序列排列
1️⃣:分析问题本质,确定可行的公差值
2️⃣:针对k=1和k=-1两种情况分别设计特殊构造方法
难度:中等
这道题目结合了数学和构造算法,需要理解等差数列和排列的性质。通过分析发现只有k=1或k=-1时有解,并且可以分别采用从中间向两边扩展或从一端交替向另一端扩展的方式构造排列。
题目三:奇偶平衡树分割问题
1️⃣:计算子树中奇数节点个数的奇偶性
2️⃣:找出"好边"并运用组合数学计算方案数
难度:中等偏难
这道题目需要理解树和子树性质,并结合奇偶性进行分析。通过DFS计算子树内奇数节点数量,找出删除后能使两侧子树奇数节点数为偶数的"好边",再利用组合数学计算从这些好边中选取不同数量边的方案数。
01. 魔法棋盘构造
问题描述
小基 正在设计一款魔法棋盘游戏。游戏棋盘由 的格子组成,每个格子上必须放置从
到
的数字。棋盘满足以下条件时,称为"魔法棋盘":
- 第一行包含
到
的所有数字,每个数字恰好出现一次
- 第二行也包含
到
的所有数字,每个数字恰好出现一次
- 对于任意两个相邻格子(上下或左右相邻)中的数字
和
,满足
(即
和
互质)
现在,小基 想知道对于给定的 值,能否构造出一个魔法棋盘。请你帮助 小基 构造一个满足条件的魔法棋盘,可以证明这样的棋盘始终存在。
输入格式
一个整数 (
),表示棋盘的列数。
输出格式
共 行,每行包含
个用空格分隔的整数,表示构造出的魔法棋盘。若存在多种可能的魔法棋盘,输出任意一种即可。
样例输入
2
样例输出
2 1
1 2
样例1 | 构造出的 |
数据范围
题解
这个问题要求我们构造一个 的矩阵,使得两行都是 1 到 n 的排列,且相邻位置的数字互质。
关键在于理解互质性质:两个数互质当且仅当它们的最大公约数为 1。相邻整数(如 3 和 4)总是互质的,因为它们没有共同因子。
考虑一种简单的构造方法:
- 将第一行设为自然顺序:1, 2, 3, ..., n
- 将第二行设为循环右移一位:2, 3, ..., n, 1
这样构造的矩阵满足条件吗?让我们验证:
- 第一行和第二行显然是排列
- 对于同一列的两个数,如第 i 列的 i 和 i+1(或者 n 和 1),它们是相邻整数,因此互质
- 对于相邻列的数,第一行中 i 和 i+1 是相邻整数,互质;第二行中 i+1 和 i+2 也是相邻整数,互质
这种构造方法的时间复杂度是 O(n),只需要简单地生成两个数组即可。在实际代码中,只需要两个循环输出这两个排列。
这个解法的优雅之处在于利用了数论中的一个基本性质:相邻整数总是互质的。无需复杂的计算或验证,只需按特定方式排列数字就能保证满足所有条件。
参考代码
- Python
import sys
input = lambda: sys.stdin.readline().strip()
def sol():
# 读取输入
n = int(input())
# 输出第一行:1, 2, ..., n
row1 = [str(i) for i in range(1, n+1)]
print(' '.join(row1))
# 输出第二行:2, 3, ..., n, 1
row2 = [str((i % n) + 1) for i in range(1, n+1)]
print(' '.join(row2))
if __name__ == "__main__":
sol()
- Cpp
#include <iostream>
using namespace std;
int main() {
// 优化输入输出
ios::sync_with_stdio(false);
cin.tie(nullptr);
// 读取输入
int n;
cin >> n;
// 输出第一行:1,2,...,n
for (int i = 1; i <= n; ++i) {
cout << i;
if (i < n) cout << " ";
else cout << "\n";
}
// 输出第二行:2,3,...,n,1
for (int i = 1; i <= n; ++i) {
// 计算循环右移后的值
int val = (i % n) + 1;
cout << val;
if (i < n) cout << " ";
else cout << "\n";
}
return 0;
}
- Java
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 读取输入
int n = Integer.parseInt(br.readLine().trim());
StringBuilder sb = new StringBuilder();
// 构造第一行:1,2,...,n
for (int i = 1; i <= n; i++) {
sb.append(i);
if (i < n) sb.append(" ");
}
sb.append("\n");
// 构造第二行:2,3,...,n,1
for (int i = 1; i <= n; i++) {
int val = (i % n) + 1;
sb.append(val);
if (i < n) sb.append(" ");
}
System.out.println(sb);
}
}
02. 音律旋律序列排列
问题描述
小毛是一位音乐家,他正在创作一个新的音乐序列。他希望通过精心设计音符的排列,让相邻音符的音高差形成一个等差数列,以创造出特殊的旋律效果。
具体来说,小毛有 个不同音高的音符,分别编号为
到
。他想将这些音符排成一个序列
,使得相邻音符的音高差的绝对值构成一个等差为
的等差数列。
形式化地,假设排列 的下标从
开始,我们定义长度为
的数组
,其中对于
,有
。若数组
是一个公差为
的等差数列,则称排列
是一个"音律序列"。
小毛给定整数 和
,请你帮助他构造一个音律序列,或者判断这样的序列是否存在。
输入格式
一行两个整数 (
,
),表示音符的数量和等差数列的公差。
输出格式
若存在满足条件的排列,第一行输出"YES",第二行输出 个整数,每个整数用空格隔开,表示满足条件的排列。若不存在则输出"NO"。
样例输入
4 -1
样例输出
YES
1 4 2 3
6 4
NO
样例1 | 排列为 [1,4,2,3],相邻元素差的绝对值为 |
样例2 | 无法构造长度为 6 且公差为 4 的音律序列。 |
数据范围
题解
这个问题要求构造一个特殊的排列,使得相邻元素差的绝对值构成公差为k的等差数列。先分析问题的本质:
假设我们构造的排列是 ,那么对应的差值序列是
。
这个差值序列需要是公差为k的等差数列,也就是形如 。
关键问题在于:什么样的k值能够让我们构造出合法的排列?
经过分析,可以发现:
- 当
时,差值序列是
- 当
时,差值序列是
- 对于其他k值,无法保证构造出的序列是一个合法的排列(会有重复元素或超出范围的元素)
为什么只有这两种情况?考虑一下,排列中的元素只能取1到n,差值的绝对值最大为n-1,最小为1。如果公差k不是1或-1,那么差值序列会迅速增大或减小,无法用1到n的排列实现。
对于k=1的情况,可以从中间元素开始,交替向两边扩展。 对于k=-1的情况,可以从一端开始,交替往另一端构造。
具体构造方法:
- 当k=1时:从
开始,交替加减递增的数
- 当k=-1时:从1开始,交替加减递减的数
通过这种方式,我们能够构造出符合条件的排列。时间复杂度为O(n),空间复杂度为O(n)。
参考代码
- Python
import sys
input = lambda: sys.stdin.readline().strip()
def solve():
# 读取输入
n, k = map(int, input().split())
# 只有k=1或k=-1时有解
if k == 1:
# 输出YES
print("YES")
# 构造排列
p = [0] * n
mid = (n + 1) // 2 # 中间位置
p[0] = mid # 起始元素
# 交替向两边扩展
for i in range(1, n):
if i % 2 == 1:
p[i] = p[i-1] + i # 向上扩展
else:
p[i] = p[i-1] - i # 向下扩展
# 输出结果
print(" ".join(map(str, p)))
elif k == -1:
# 输出YES
print("YES")
# 构造排列
p = [0] * n
p[0] = 1 # 起始元素
# 交替加减构造
for i in range(1, n):
d = n - i # 递减的差值
if i % 2 == 1:
p[i] = p[i-1] + d
else:
p[i] = p[i-1] - d
# 输出结果
print(" ".join(map(str, p)))
else:
# 其他情况无解
print("NO")
if __name__ == "__main__":
solve()
- Cpp
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 优化输入输出
ios::sync_with_stdio(false);
cin.tie(nullptr);
// 读取输入
int n, k;
cin >> n >> k;
// 判断是否有解
if (k == 1) {
// 输出YES
cout << "YES" << endl;
// 构造排列
vector<int> p(n);
int mid = (n + 1) / 2;
p[0] = mid;
for (int i = 1; i < n; ++i) {
if (i % 2 == 1)
p[i] = p[i-1] + i;
else
p[i] = p[i-1] - i;
}
// 输出结果
for (int i = 0; i < n; ++i) {
cout << p[i] << (i == n-1 ? '\n' : ' ');
}
}
else if (k == -1) {
// 输出YES
cout << "YES" << endl;
// 构造排列
vector<int> p(n);
p[0] = 1;
for (int i = 1; i < n; ++i) {
int d = n - i;
if (i % 2 == 1)
p[i] = p[i-1] + d;
else
p[i] = p[i-1] - d;
}
// 输出结果
for (int i = 0; i < n; ++i) {
cout << p[i] << (i == n-1 ? '\n' : ' ');
}
}
else {
// 其他情况无解
cout << "NO" << endl;
}
return 0;
}
- Java
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 读取输入
String[] parts = br.readLine().trim().split(" ");
int n = Integer.parseInt(parts[0]);
int k = Integer.parseInt(parts[1]);
// 判断是否有解
if (k == 1) {
// 输出YES
System.out.println
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
互联网刷题笔试宝典,这里涵盖了市面上大部分的笔试题合集,希望助大家春秋招一臂之力