2025 年河南工业大学天梯赛 题解
L1-1 哪吒的宣言
C 语言
#include <stdio.h>
int main(void) {
printf("If the world won't accept me, I'll twist it to my will!");
return 0;
}
Python
print("If the world won't accept me, I'll twist it to my will!")
L1-2 哪吒求和
#include<stdio.h>
int a[12];
int main()
{
int sum=0;
for(int i=1;i<=10;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
printf("%d",sum);
return 0;
}
L1-3 找到HarryPotter
读入一个字符串然后遍历一遍即可,找到字符串中为h的字符,然后将它替换
#include<iostream>
using namespace std;
signed main() {
string s;
cin >> s;
for (int i = 0; i < s.size(); i++) {
if (s[i] == 'h') {
s[i] = '#';
}
}
cout << s << endl;
return 0;
}
L1-4 Shinji Ikari
只需要判断每个下标是否是质数即可。该题数据量较小,可暴力判断。
注意1不是质数。
#include <bits/stdc++.h>
#define pii pair<int,int>
#define piii pair<int, pair<int, int>>
#define int long long
using namespace std;
bool isprime(int x) {
if (x == 1) return 0;
if (x == 2 || x == 3) return 1;
for (int i = 2; i <x; i++) { //此处可直接暴力到x-1
if (x % i == 0) {
return 0;
}
}
return 1;
}
void solve() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
if (!isprime(i)) cout << x << " ";
}
}
signed main() {
int T = 1;
while (T--) {
solve();
}
return 0;
}
L1-5 零件检测
通读题干后可以得出题目要求的是n次循环中每个零件的实际误差之和除以n,与p进行比较,如果该平均值不大于p,输出Yes,否则输出No,并保留6位小数输出实际误差。 代码如下:
#include<stdio.h>
int main()
{
int n ;
double k , p ;
scanf("%d%lf%lf",&n , &k , &p) ;
double sum = 0 ;
for(int i = 1 ; i <= n ; i ++) {
double x ;
scanf("%lf", &x) ;
if(x - k >= 0) sum += x - k ;
else sum += k - x ;
}
sum = (1.00 * sum) / (1.00 * n) ;
if(sum <= p) printf("Yes\n") ;
else printf("No %6lf\n" , sum) ;
return 0 ;
}
L1-6 用电量预测误差
按题意来,无需多言。
C 语言
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int P[24], A[24];
for (int i = 0; i < 24; ++i) {
scanf("%d", &P[i]);
}
for (int i = 0; i < 24; ++i) {
scanf("%d", &A[i]);
}
int maxDiff = 0;
for (int i = 0; i < 24; ++i) {
int diff = abs(P[i] - A[i]);
if (diff > maxDiff) {
maxDiff = diff;
}
}
printf("%d\n", maxDiff);
return 0;
}
Python
P = map(int, input().split())
A = map(int, input().split())
print(max(abs(p - a) for p, a in zip(P, A)))
L1-7 跨文化交际
遍历字符串,如果在原字符串S中遇到字符C,输出P字符串即可。请注意吸收换行符,代码如下:
#include<stdio.h>
#include<string.h>
const int N = 2e5 + 10 ;
int main()
{
char s[N] ;
scanf("%s",s) ;
getchar() ;
char c ;
scanf("%c" , &c) ;
getchar() ;
char p[N] ;
scanf("%s" , p) ;
for(int i = 0 ; i < strlen(s) ; i ++) {
if(s[i] != c) {
printf("%c" , s[i]) ;
} else {
printf("%c" , s[i]) ;
for(int j = 0 ; j < strlen(p) ; j ++) {
printf("%c" , p[j]) ;
}
}
}
return 0 ;
}
L1-8 马拉松站点补给
通过循环模拟分配过程:
初始化长度为num_people的全零数组
定义当前应分配数量current,从1开始递增
循环分配能量胶,每次取min(current,剩余数量)
利用取模运算实现循环索引
#include <vector>
#include <algorithm>
#include<iostream>
int res[10000] = {0};
void distributeSupplies(int supplies, int num_stations) {
int current = 1;
int index = 0;
while (supplies > 0) {
int allocation = std::min(current, supplies);
res[index % num_stations] += allocation;
supplies -= allocation;
current++;
index++;
}
} int main() {
int n, m;
std::cin >> n >> m;
distributeSupplies(n, m);
for (int i = 0; i < m; i++)
{
std::cout << res[i] << " ";
} return 0;
}
复杂度分析
时间复杂度:O(√n),因每次分配量递增,循环次数约为√(2*n)
空间复杂度:O(m),仅需维护结果数组
该方法通过循环和取模运算高效实现了符合赛事规则的分配过程,确保正确处理边界情况
L2-1 炼化
排序问题,数据量比较小,可以直接使用冒泡排序进行排序。
#include<stdio.h>
int a[1005];
int n;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<n;i++)
{
for(int j=1;j<=n-i;j++)
{
if(a[j]>a[j+1])
{
int t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}
for(int i=1;i<=n;i++)
{
printf("%d",a[i]);
if(i!=n)
printf(" ");
else
printf("\n");
}
printf("%d",a[n]);
return 0;
}
L2-2 勇闯玉虚宫
本题有两个坑点:
- 一个就是k的值可能过大,导致越界,所以在暴力遍历数组下标的时候要判断一下会不会越界
- 另外一个就是最后的和会爆 int 所以要开long long
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main() {
int n;
cin >> n;
vector<vector<int>> a(n + 1, vector<int> (n + 1));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> a[i][j];
}
}
int x, y, k;
cin >> x >> y >> k;
int sum = 0;
for (int i = x - k / 2; i <= x + k / 2; i++) {
for (int j = y - k / 2; j <= y + k / 2; j++) {
if (i <= 0 || i > n || j > n || j <= 0) continue;
sum += a[i][j];
}
}
cout << sum << endl;
return 0;
}
L2-3 MyGO!!!!!
首先我们需要搞懂两个下标,一个是有效音符的下标,一个是给定的音符串的下标。搞懂这个,做法就很清晰了。其次,此题目判断质数的时候,不能再暴力到x-1,必须到根号x的位置。
#include <bits/stdc++.h>
using namespace std;
bool isprime(int x) {
if (x == 1) return 0;
for (int i = 2; i * i <= x; i++) {
if (x % i == 0) {
return 0;
}
}
return 1;
}
int main() {
int n, k;
int atleast;
cin >> n >> k >> atleast;
int idx = 1; //总音符串中的下标
int tr = 1; //实际有效音符下标
vector<int> arr(n + 1);
for (int i = 1; i <= n; i++) cin >> arr[i];
for (; idx <= n; idx++) {
if (arr[idx] != (1 + (tr - 1) * k) * (1 + (tr - 1) * k)) {
if (!isprime(arr[idx])) {
cout << "Wrong!" << endl;
cout << idx << endl;
return 0;
}
} else {
tr++;
}
}
if (tr >= atleast) {
cout << "It's MyGO!!!!!" << endl;
} else {
cout << "Useless!" << endl;
}
}
L2-4 空间优化
本题主要考察对于结构体构造,简单暴力查重能力的考查,在c++语言中class与c语言的struct高度类似,本题用class实现,先开一个class数组存放id和email的信息,然后从头开始遍历将所有email相等的id保留第一个即可
#include <vector>
#include <unordered_map>
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
struct Person {
int id;
string email;
};
Person p[1000];
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> p[i].id;
cin >> p[i].email;
}
for (int i = 0; i < n; i++) {
if (p[i].email != "") {
for (int j = i + 1; j < n; j++) {
if (p[i].email == p[j].email) {
p[j].email = "";
}
}
}
}
for (int i = 0; i < n; i++) {
if (p[i].email != "") {
cout << p[i].id << " " << p[i].email << endl;
}
}
return 0;
}
L3-1 服务器性能排行榜
在竞赛中,一般认为每秒可以执行 5×10⁸ 次运算。
本题 n 的数量级达到 10⁵。排序时必须使用时间复杂度为 O(log n) 的排序算法。
删除数据时,不可暴力遍历,需要使用高效的数据结构。用集合或映射能实现最快 O(1) 时间复杂度内删除元素。
C++
以下 main 函数的前两行代码可以加快读入数据速度,是竞赛常用技巧。
#include <algorithm>
#include <iostream>
#include <unordered_set>
#include <vector>
using namespace std;
struct Server {
int id;
int responseTime;
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<Server> servers;
for (int i = 0; i < n; i++) {
int id, responseTime;
cin >> id >> responseTime;
servers.push_back({id, responseTime});
}
int m;
cin >> m;
unordered_set<int> toDelete;
for (int i = 0; i < m; i++) {
int id;
cin >> id;
toDelete.insert(id);
}
// 过滤掉需要删除的服务器
vector<Server> remaining;
for (const auto &s : servers) {
if (toDelete.find(s.id) == toDelete.end()) {
remaining.push_back(s);
}
}
// 按照响应时间升序,若相同则按 ID 升序
sort(remaining.begin(), remaining.end(),
[](const Server &a, const Server &b) {
return a.responseTime == b.responseTime
? a.id < b.id
: a.responseTime < b.responseTime;
});
// 输出排序后服务器 ID
for (const auto &s : remaining) {
cout << s.id << "\n";
}
return 0;
}
Python
在 Python 中,多次调用 `input()` 函数速度较慢,因此一次读入所有数据并转换成数字。
import sys
input = map(int, sys.stdin.read().split())
n = next(input)
servers = {}
for _ in range(n):
id = next(input)
time = next(input)
servers[id] = time # 在 servers 中保存 id:time 映射
m = next(input)
for _ in range(m):
del_id = next(input) # 读入需要删除的 ID
servers.pop(del_id, None) # 删除 del_id
# 对于一对 id:time 优先以 time 排序,其次是 id
sorted_servers = sorted(servers.items(), key=lambda x: (x[1], x[0]))
# 输出答案
sys.stdout.write("\n".join(str(id) for id, _ in sorted_servers))
L3-2 最小的数字
本题暴力遍历每个操作的话会超时,但是我们可以发现一个性质:
- 当改变的值包括最小值的时候,最小值-- / ++
- 当改变值不包括最小值的时候,最小值不变。
- 而又因为每次操作数字只会改变1,所以当第二大的数字被操作时,即使它--,也不会比最小的数字更小。
所以综上,我们只需要维护最小的数字看它是否增加或者减少
#include<bits/stdc++.h>
using namespace std;
signed main() {
int n, m;
cin >> n >> m;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
int Min = *min_element(a.begin() + 1, a.end());
while(m--) {
int op, l, r;
cin >> op >> l >> r;
if (Min >= l && Min <= r) Min += op;
cout << Min << endl;
}
return 0;
}
L3-3 Just Monika
宽度优先搜索(BFS)。在bfs中,我们每次往四周走一层,在这样的前提下第一次到达某个点(x,y)距离一定是最近的。前提是每条路线的长度都一样。
我们用队列来存储每次延申的时候四个方向的点。由于要求字典序最小,故按照上下左右四个方向把待搜索的点加入队列。用vis来保证一个点只搜索一次,用prev来记录每个点的前驱位置,用prevDir来记录从哪个方向转到x y这个点。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
int dx[] = {-1, 1, 0, 0}; // 上、下、左、右
int dy[] = {0, 0, -1, 1};
int dir[] = {1, 2, 3, 4}; // 1=上, 2=下, 3=左, 4=右
void solve() {
int n, m;
cin >> n >> m;
vector<vector<int>> arr(n, vector<int>(m));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> arr[i][j]; //邻接表存点之间的关系。
}
}
vector<vector<int>> dist(n, vector<int>(m, 1e9));
vector<vector<int>> vis(n, vector<int>(m, 0));
vector<vector<int>> prevDir(n, vector<int>(m, -1));
vector<vector<pii>> prev(n, vector<pii>(m, {-1, -1}));
queue<pii> q;
dist[0][0] = 0;
q.push({0, 0});
while (!q.empty()) {
pii zz = q.front();
q.pop();
int x = zz.first, y = zz.second;
if (vis[x][y]) continue;
vis[x][y] = 1;
for (int i = 0; i < 4; i++) {
int nx = x + dx[i], ny = y + dy[i];
if (nx >= 0 && nx < n && ny >= 0 && ny < m && arr[nx][ny] == 1) {
if (dist[nx][ny] > dist[x][y] + 1) {
dist[nx][ny] = dist[x][y] + 1;
q.push({nx, ny});
prev[nx][ny] = {x, y};
prevDir[nx][ny] = dir[i]; //代表到达nx ny这个点是从dir[i]方向转过来的。
}
}
}
}
if (dist[n-1][m-1] == 1e9) { //代表不能到达。
cout << "Just Monika" << endl;
return;
}
string path = "";
int x = n - 1, y = m - 1;
while (!(x == 0 && y == 0)) {
path += char('0' + prevDir[x][y]);
tie(x, y) = prev[x][y];
}
reverse(path.begin(), path.end());
cout << path << endl;
cout << path.size() << endl;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T = 1;
while (T--) {
solve();
}
}

浙公网安备 33010602011771号