The 2nd GUAT Collegiate Programming Contest (Round 1)
第二届 GUAT大学生程序设计大赛 第一场 题解(A-M)
前言
比赛的内容主要包括计算机科学的常用算法,基本的计算理论,(如:离散数学,具体数学,组合数学基础),数据结构基础,程序设计语言(规定是C/C++或者是Java、Python)。在本项比赛中考察学生的不仅仅是能够完成指定任务的程序,更要求在完成程序的功能的基础之上提高程序的运行效率与空间占用率。涵盖的考点范围:数学计算,排序,字符串处理,简单算法(搜索,枚举,查找,计数,前缀和等),简单数论,简单图论,简单动态规划,数据结构:数组,对象/结构,字符串,队列,栈,树,图等。
题解
A、Equational?
题意
给定一个分数
分子
题解
不妨假设下式已成立:
令
则
且无论分子还是分母均为自然数
由鸽巢定理(抽屉原理)可知:分母必须大于等于
即有通解:
只需要将上述通解的分子通分为相同数,即为此题的解。不妨将分母取6,得:
故容易得到:
时间复杂度:O(1) 空间复杂度:O(1)
代码实现
C++
#include<iostream> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); using namespace std; int T; int a, b; /** * ∵1 = 1/2 + 1/3 + 1/6 * 设 a/b 为 x,则: * 1 * x = 1/2 * x + 1/3 * x + 1/6 * x * ∴c1 = c2 = c3 = c = a; d1 = 2 * b, d2 = 3 * b, d3 = 6 * b */ void solve() { cin >> a >> b; cout << a << ' ' << 2 * b << ' ' << a << ' ' << 3 * b << ' ' << a << ' ' << 6 * b << '\n'; } int main() { IOS cin >> T; while (T --) solve(); return 0; }
B、Characters games
题意
给定一个字符串,以
例如:
问:最后每个出现次数不为0的字符,出现的次数分别是多少?按字典序输出。
题解
双指针解法
当读取到一个字符时,即可将第一个指针指向该字符之后的两个位置,即数字开始的位置
然后另一个指针从第一个之后的第一个位置开始从前往后遍历,直至扫描到有括号停止
两个指针之间的数值,便是当前字符连续出现的次数
值得注意的是,一个字符是可以在这个字符串中出现多次的,因此统计的值需要累加
时间复杂度:O(n) 空间复杂度:O(1)
代码实现
C++
#include<iostream> #include<cstring> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); using namespace std; string s; long long mp[26]; int main() { IOS cin >> s; for (int i = 0, j, k = s.size(); i < k; ++ i) { if (islower(s[i])) { long long num = 0; for (j = i + 2; s[j] != ')'; ++ j) { num = num * 10LL + s[j] - '0'; } mp[s[i] - 'a'] += num; i = j; } } for (auto &it: mp) { if (it) cout << it << ' '; } return 0; }
Go
package main import ( "bufio" "fmt" "os" "strconv" ) func main() { in := bufio.NewReader(os.Stdin) out := bufio.NewWriter(os.Stdout) defer out.Flush() var s string _, _ = fmt.Fscan(in, &s) l := len(s) cnt := [30]int{} for i := 0; i < l; i++ { ci := s[i] i += 2 j := i for s[i] != ')' { i++ } num, _ := strconv.Atoi(s[j:i]) cnt[ci-'a'] += num } for i := 0; i < 30; i++ { if cnt[i] > 0 { _, _ = fmt.Fprintf(out, "%d ", cnt[i]) } } _, _ = fmt.Fprintln(out) }
Java
import java.util.Arrays; import java.util.HashMap; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scan = new Scanner(System.in); String str = scan.next(); Integer nums[] = new Integer[26]; Arrays.fill(nums,0); char s[] = str.toCharArray(); for(int i = 0; i < str.length(); i++){ if(s[i] == '('){ for(int j = i + 1; j < str.length(); j++){ if(s[j] == ')'){ String temp = str.substring(i + 1,j); nums[(s[i - 1] - 'a')] += Integer.valueOf(temp); i = j; break; } } } } for(int i = 0; i < 26; i++){ if(nums[i] != 0) System.out.print(nums[i] + " "); } System.out.println(); } }
C、Orienteering
题意
类似于校园跑,要按顺序经过一些给定的点位。从一个点位到达另一个点位,优先选择一条最短路径。若有多条不同的路径都是最短距离,优先选择经过的点数最少的路径。
题解
Floyd算法求最短路,并且额外开一个数组,存储经过的点的数量
时间复杂度:O(
代码实现
C++
#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); using namespace std; const int N = 207; int n, m, p, a, b, u, v, w; int parr[N]; int mt[N][N]; int dis[N][N]; int edge[N][N]; void solve() { memset(dis, 0x3f, sizeof(dis)); memset(edge, 0x3f, sizeof(edge)); scanf("%d%d%d", &n, &m, &p); scanf("%d%d", &a, &b); for (int i = 1; i <= p; i ++) { scanf("%d", &parr[i]); } parr[0] = a; parr[++ p] = b; for (int i = 1; i <= m; i ++) { scanf("%d%d%d", &u, &v, &w); mt[u][v] = mt[v][u] = w; edge[u][v] = edge[v][u] = 1; dis[u][v] = dis[v][u] = w; } for (int i = 1; i <= n; i ++) { dis[i][i] = edge[i][i] = 0; } for (int k = 1; k <= n; k ++) { //floyd for (int i = 1; i <= n; i ++) { for (int j = 1; j <= n; j ++) { if (dis[i][k] + dis[k][j] < dis[i][j]) { dis[i][j] = dis[i][k] + dis[k][j]; edge[i][j] = edge[i][k] + edge[k][j]; } else if (dis[i][k] + dis[k][j] == dis[i][j]) { edge[i][j] = min(edge[i][j], edge[i][k] + edge[k][j]); } } } } int res1 = 0, res2 = 0; for (int i = 1; i <= p; i ++) { res1 += dis[parr[i - 1]][parr[i]]; res2 += edge[parr[i - 1]][parr[i]]; } printf("%d %d\n", res1, res2); } int main() { IOS; int _t = 1; while (_t--) solve(); return 0; }
Go
package main import ( "bufio" "fmt" "math" "os" ) func main() { in := bufio.NewReader(os.Stdin) out := bufio.NewWriter(os.Stdout) defer out.Flush() var n, m, p int _, _ = fmt.Fscan(in, &n, &m, &p) var a, b int _, _ = fmt.Fscan(in, &a, &b) // 需要走的路径 pa := make([]int, p+2) pa[0] = a pa[p+1] = b for i := 1; i <= p; i++ { _, _ = fmt.Fscan(in, &pa[i]) } // 图的路径 dis := make([][]int, n+1) way := make([][]int, n+1) for i := range dis { dis[i] = make([]int, n+1) } for i := range way { way[i] = make([]int, n+1) } var u, v, w int for i := 0; i < m; i++ { _, _ = fmt.Fscan(in, &u, &v, &w) dis[u][v] = w dis[v][u] = w way[u][v] = 1 way[v][u] = 1 } for i := 1; i <= n; i++ { for j := 1; j <= n; j++ { if dis[i][j] == 0 { dis[i][j] = math.MaxInt16 } } dis[i][i] = 0 } sumw := 0 sump := 0 for k := 1; k <= n; k++ { for x := 1; x <= n; x++ { for y := 1; y <= n; y++ { if dis[x][k]+dis[k][y] < dis[x][y] { dis[x][y] = dis[x][k] + dis[k][y] way[x][y] = way[x][k] + way[k][y] } else if dis[x][k]+dis[k][y] == dis[x][y] && way[x][k]+way[k][y] < way[x][y] { way[x][y] = way[x][k] + way[k][y] } } } } for i := 1; i <= p+1; i++ { sumw += dis[pa[i-1]][pa[i]] sump += way[pa[i-1]][pa[i]] } _, _ = fmt.Fprintf(out, "%d %d\n", sumw, sump) }
D、Layers of progressive
题意
给点初始血量
在每个关卡会给个四个正整数
其中,
1 | 2 | 3 | 4 |
---|---|---|---|
+ | - | * | / |
例如:
问:在游戏结束后,能剩余的最大血量是多少?
题解
不妨假设:每关的血量值越高,最后剩余的血量值就会越高
证明:
不妨令前一步的结果为
操作:结果 = 操作:结果 = 操作:结果 = 操作:结果 =
对于1:
不妨令
根据上式,可列出方程:
对于2:
不妨令
根据上式,列出方程:
对于3:
根据题意,列出方程:
方程左右两边对
那么方程
对于4:
根据题意,列出方程:
方程左右两边对
那么方程
由上述证明,可得结论:每一步最大化血量,最后剩余的血量值就会越高
时间复杂度:O(n) 空间复杂度:O(1)
代码实现
C++
#include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); typedef long long ll; using namespace std; int m; ll n; ll calc(int p, int q) { ll val = n; switch(p) { case 1: val += q; break; case 2: val -= q; break; case 3: val *= q; break; case 4: val /= q; break; } return val; } void solve() { int a, b, c, d; cin >> a >> b >> c >> d; n = max(calc(a, c), calc(b, d)); } int main() { IOS cin >> n >> m; while (m --) solve(); cout << n; return 0; }
Java
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scan = new Scanner(System.in); Long n; Integer m; n = scan.nextLong(); m = scan.nextInt(); for(int i = 0; i < m; i++){ Integer a,b,c,d; a = scan.nextInt(); b = scan.nextInt(); c = scan.nextInt(); d = scan.nextInt(); Long temp1 = n,temp2 = n; switch (a){ case 1: temp1 += c; break; case 2: temp1 -= c; break; case 3: temp1 *= c; break; case 4: temp1 /= c; break; } switch (b){ case 1: temp2 += d; break; case 2: temp2 -= d; break; case 3: temp2 *= d; break; case 4: temp2 /= d; break; } if(temp1 > temp2){ n = temp1; }else{ n = temp2; } //System.out.println(n); } System.out.println(n); } }
E、Step 20
题意
在二维网格图中,可以朝向上、下、左、右进行移动一格,但不能移动到有障碍物的格子。给点起始位置(
题解
思路1:广度优先搜索
横纵坐标的范围均为[
那么若直接开一个
观察题目信息,可知:给点的起始坐标(
那么不妨设置两个偏移量
通过给坐标设置偏移量以后,即可得到如下二维坐标图:
例如:起始坐标(
我们只需要维护偏移后横纵坐标均落在[
由于加上了步数的限制,因此抵达一个坐标点,并不一定就是目标步数
所以不可以简单地用bool
此时需要再引入一个新的维度,亦即需要以bool
bool
其他的操作和普通的广度优先搜索类似
时间复杂度:O(
思路2:动态规划
二维网格图优化思路类似于思路1,都是将坐标进行偏移映射
定义int
状态转移方程:
二维矩阵初始化:除了
代码实现
C++(思路1)
#include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define OBSTACLE 1 #define ROAD 0 using namespace std; typedef tuple<int, int, int> TP; constexpr static int DIRS[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; const int MX = 40, MI = 0; int T, a, b, c, d, m, q; int offset_x, offset_y; int e[42][42]; bool vis[42][42][21]; //特殊测试用例 //(a,b)可达 但其他点均不可达 问(a,b)可不可达 void init() { for (int i = 0; i < 42; ++ i) { for (int j = 0; j < 42; ++ j) { for (int k = 0; k <= 20; ++ k) { vis[i][j][k] = false; } e[i][j] = ROAD; } } } inline bool check(int r, int c) { return r <= MX && r >= MI && c <= MX && c >= MI; } void bfs() { queue<TP> que; que.push(TP(20, 20, 0)); vis[20][20][0] = true; while (!que.empty()) { TP tp = que.front(); que.pop(); int x = get<0>(tp), y = get<1>(tp), z = get<2>(tp); for (int i = 0; i < 4; ++ i) { int nex = x + DIRS[i][0], ney = y + DIRS[i][1]; if (check(nex, ney) && !vis[nex][ney][z + 1] && e[nex][ney] == ROAD) { if (z < 19) que.push(TP(nex, ney, z + 1)); vis[nex][ney][z + 1] = true; } } } } void solve() { init(); cin >> a >> b >> m >> q; offset_x = 20 - a, offset_y = 20 - b;//设置偏移量 for (int i = 0; i < m; ++ i) { cin >> c >> d; c += offset_x; d += offset_y; if (check(c, d)) {//是否在图内 e[c][d] = OBSTACLE;//障碍物 } } bfs();//广度优先遍历 while (q --) { cin >> c >> d; c += offset_x; d += offset_y; if (check(c, d) && vis[c][d][20]) { cout << "YES" << endl; } else { cout << "NO" << endl; } } } int main() { IOS cin >> T; while (T --) { solve(); } return 0; }
C++(思路2)
#include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); using namespace std; int mp[43][43], dp[21][43][43]; int fstX, fstY; int ret[2]; bool inRange(int y, int x) { return (fstY - 20 <= y && y <= fstY + 20) && (fstX - 20 <= x && x <= fstX + 20); } void getIdx(int y, int x) { ret[0] = y - fstY + 21; ret[1] = x - fstX + 21; } void solve() { memset(dp, 0, sizeof(dp)); memset(mp, 0, sizeof(mp)); int a, b, m, q, c, d, e, f; scanf("%d%d%d%d", &a, &b, &m, &q); fstX = a; fstY = b; for (int i = 1; i <= m; ++ i) { scanf("%d%d", &c, &d); if (inRange(d, c)) { getIdx(d, c); mp[ret[0]][ret[1]] = 1; } } getIdx(fstY, fstX); dp[0][ret[0]][ret[1]] = 1; for (int i = 1; i <= 20; ++ i) { for (int j = 1; j <= 41; ++ j) { for (int k = 1; k <= 41; ++ k) { if (!mp[j][k]) { dp[i][j][k] = dp[i - 1][j - 1][k] | dp[i - 1][j][k - 1] | dp[i - 1][j + 1][k] | dp[i - 1][j][k + 1]; } } } } while (q --) { scanf("%d%d", &e, &f); if (inRange(f, e)) { getIdx(f, e); printf("%s\n", dp[20][ret[0]][ret[1]] ? "YES" : "NO"); } else { printf("NO\n"); } } } int main() { IOS; int _t; scanf("%d", &_t); while (_t --) solve(); return 0; }
F、Square toy
题意
给定一个共有
对方块玩具会改变四次重力,方向分别为:右、上、左、下。问:依次改变完全部的重力方向后,每一列的个数是多少?
题解
下述的行的数量和列的数量,指的均为一行/列的方块数量。
重力向右:对于行的数量不会发生变化,列的数量变为从右向左递减。
重力向左:对于行的数量不会发生变化,列的数量变为从左向右递减。
重力向上:对于列的数量不会发生变化,行的数量变为从上向下递减。
重力向下,对于列的数量不会发生变化,行的数量变为从下向上递减。
起始状态重力向下。所以易知排序即为最后的结果。
时间复杂度:O(nlogn) 空间复杂度:O(n)
代码实现
C++
#include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); using namespace std; int n; int a[1000007]; int main() { IOS cin >> n; for (int i = 0; i < n; ++ i) cin >> a[i]; sort(a, a + n, [&](int &val1, int &val2) { return val1 > val2; }); for (int i = 0; i < n; ++ i) cout << a[i] << ' '; return 0; }
Go
package main import ( "bufio" "fmt" "os" "sort" ) func main() { in := bufio.NewReader(os.Stdin) out := bufio.NewWriter(os.Stdout) defer out.Flush() var n int _, _ = fmt.Fscanln(in, &n) a := make([]int, n) for i := 0; i < n; i++ { _, _ = fmt.Fscan(in, &a[i]) } sort.Slice(a, func(i, j int) bool { return a[i] > a[j] }) for i := 0; i < n; i++ { _, _ = fmt.Fprintf(out, "%d ", a[i]) } _, _ = fmt.Fprintln(out) }
G、Types of words
题意
问一个四字成语的类型
题解
假设成语存于字符串
代码实现上,只需要嵌套两层for循环,查看该字符在当前位置之前的位置是否已经出现过。若出现过,则记录为与之相同的类型;若未出现过,则记录为最新的类型。
时间复杂度:O(
代码实现
C++
#include<iostream> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); using namespace std; int T; char s[5], t[5]; void solve() { cin >> s; char ch = 'A'; for (int i = 1; i < 4; ++ i) { bool flag = false; for (int j = 0; j < i; ++ j) { if (s[i] == s[j]) { t[i] = t[j]; flag = true; break; } } if (!flag) t[i] = ++ ch; } cout << t << '\n'; } int main() { IOS t[0] = 'A', t[4] = '\0'; cin >> T; while (T --) solve(); return 0; }
Java
import java.util.Scanner; public class Main { public static void main(String[] args){ Scanner scan = new Scanner(System.in); int n = scan.nextInt(); for (int i = 0; i < n; i++) { String str = scan.next(); char s[] = str.toCharArray(); char ans[] = new char[4]; ans[0] = 'A'; char ch = 'A'; for(int j = 1; j < 4; j++){ Integer judge = 0; for(int k = 0; k < j; k++){ if(s[k] == s[j]){ ans[j] = ans[k]; judge = 1; break; } } if(judge == 0){ ans[j] = ++ch; } } System.out.println(ans); } } }
H、Card game
题意
对于
问:全部卡牌被抽取完成后,积分最大者为胜者。输出全部胜者。
题解
维护每个玩家的总得分,总得分除以游戏轮次即为平均数
用map<int, int>维护每个数的出现次数,出现次数最多者为众数
时间复杂度:O(nlogn) 空间复杂度:O(n)
代码实现
C++
#include<bits/stdc++.h> #define PII pair<int, int> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); typedef long long ll; using namespace std; const int N = 1e5 + 7; int n, m, w; struct Node { int id;//玩家编号 ll score;//分数 ll sum;//全部数值之和 map<int, int> mp;//存每个数出现的次数 PII p;//first为众数,second为数目 }; int main() { IOS cin >> n >> m; vector<Node> node(n); for (int i = 0; i < n; ++ i) { cin >> node[i].id; node[i].sum = node[i].score = node[i].p.first = node[i].p.second = 0; } for (int j = 0; j < m; ++ j) { cin >> w; int i = j % n; node[i].sum += w; node[i].mp[w] ++; if (node[i].mp[w] > node[i].p.second) { node[i].p.first = w; node[i].p.second = node[i].mp[w]; } else if (node[i].mp[w] == node[i].p.second && w < node[i].p.first) { node[i].p.first = w; } node[i].score += node[i].sum / (j / n + 1);//平均值 node[i].score += node[i].p.first;//众数 } sort(node.begin(), node.end(), [&](Node &it1, Node &it2) { if (it1.score != it2.score) return it1.score > it2.score; return it1.id < it2.id; }); cout << node[0].id << ' '; for (int i = 1; i < n && node[i].score == node[i - 1].score; ++ i) { cout << node[i].id << ' '; } return 0; }
Java
import java.util.Arrays; import java.util.HashMap; import java.util.Scanner; import java.util.stream.Collectors; class People { Integer No; Long sum; Long garde; HashMap<Long, Integer> map; } public class Main { // 获取众数 static Long GetMode(HashMap<Long, Integer> hashMap) { Integer max = -1; Long ans = 0L; for (Long key : hashMap.keySet().stream().sorted().collect(Collectors.toList())) { Integer value = hashMap.get(key); if (value > max) { max = value; ans = key; } } return ans; } public static void main(String[] args) { Scanner scan = new Scanner(System.in); int n, m; n = scan.nextInt(); m = scan.nextInt(); People[] people = new People[n + 10]; Long max = -1L; people[0] = new People(); for (int i = 1; i <= n; i++) { People p = new People(); p.No = scan.nextInt(); p.sum = 0L; p.garde = 0L; p.map = new HashMap<>(); people[i] = p; } Long round = 0L; // 模拟摸牌 for (int i = 1; i <= m; i++) { Long temp = scan.nextLong(); int index = i % n; if (index == 0) { index = n; } people[index].sum += temp; // map用于记录每个数出现的次数 if (!people[index].map.containsKey(temp)) people[index].map.put(temp, 1); else { people[index].map.put(temp, people[index].map.get(temp) + 1); } // 摸完一轮时,计算分数 if (index % n == 0) { round++; for (int j = 1; j <= n; j++) { people[j].garde += people[j].sum / round; people[j].garde += GetMode(people[j].map); } } } Arrays.sort(people, 1, n, (o1, o2) -> { if (o1.garde.equals(o2.garde)) { return o1.No - o2.No; } return o2.garde.compareTo(o1.garde); }); max = people[1].garde; for (int i = 1; i <= n; i++) { if (people[i].garde.equals(max)) System.out.print(people[i].No + " "); } System.out.println(); } }
I、3²+4²=5²
题意
输入一个正整数
题解
判断下式是否成立即可:
时间复杂度:O(1) 空间复杂度:O(1)
代码实现
C++
#include<iostream> #include<algorithm> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); using namespace std; int T; long long a[3]; inline bool isRt() { sort(a, a + 3); return a[0] * a[0] + a[1] * a[1] == a[2] * a[2]; } void solve() { for (int i = 0; i < 3; ++ i) cin >> a[i]; if (isRt()) { cout << "Yes\n"; } else { cout << "No\n"; } } int main() { IOS cin >> T; while (T --) { solve(); } return 0; }
Java
import java.util.Arrays; import java.util.Scanner; public class Main { static String Judge(Integer nums[]){ if(((nums[0] * nums[0]) + (nums[1] * nums[1])) == (nums[2] * nums[2])) return "Yes"; return "No"; } public static void main(String[] args) { Scanner scan = new Scanner(System.in); Integer n = scan.nextInt(); Integer nums[] = new Integer[3]; for(int i = 0; i < n; i++){ for(int j = 0; j < 3; j++){ nums[j] = scan.nextInt(); } Arrays.sort(nums); System.out.println(Judge(nums)); } } }
J、Palindromic number manipulators
题意
易枚举出正整数范围内的回文数:
会进行两次选取,范围分别为[
意为:截取从第
你需要将第一个字符串变为第二个字符串,你可以选择的操作有:
- 增加一个数字
- 删除一个数字
- 修改一个数字
你可以进行操作任意次,但每次只能选择其中一种操作。
问:将第一个字符串变为第二个字符串,最少需要花费的操作次数是多少?
题解
提示信息:第
根据提示信息,可知若从
枚举思路:分为奇数个数位和偶数个数位进行从小到大枚举,详细枚举方法见参考代码
若不知道如何线性枚举回文数,也可以使用打表法。
将第一个字符串变为第二个字符串,只需要线性DP 编辑距离 即可。
时间复杂度:O(
代码实现
C++
#include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); typedef long long ll; using namespace std; const int N = 1007; int m, n; int dp[N][N]; int l[2], r[2]; string s[2]; vector<ll> hw; void init(ll val) { ll up = 1;//若会越界就开long long char s[100]; sprintf(s, "%lld", val); int len = strlen(s); len = (len - 1) / 2; while (len --) up *= 10; for (ll u = 1; u <= up; u *= 10) { //枚举奇数长度的回文数 for (ll i = u, j = u * 10; i < j; ++ i) { ll x = i; ll y = i; x /= 10;//去掉最低位 while (x) { y = y * 10 + x % 10; x /= 10; } hw.emplace_back(y); } //枚举偶数长度的回文数 for (ll i = u, j = u * 10; i < j; ++ i) { ll x = i; ll y = i; while (x) { y = y * 10 + x % 10; x /= 10; } hw.emplace_back(y); } } } void solve() { for (int i = 0; i < 2; ++ i) { for (int j = l[i] - 1; j < r[i]; ++ j) { s[i] += to_string(hw[j]); } } m = s[0].size(), n = s[1].size(); for (int i = 1; i <= m; ++ i) dp[i][0] = i; for (int i = 1; i <= n; ++ i) dp[0][i] = i; for (int i = 1; i <= m; ++ i) { for (int j = 1; j <= n; ++ j) { if (s[0][i - 1] == s[1][j - 1]) { dp[i][j] = dp[i - 1][j - 1]; } else { dp[i][j] = min(dp[i - 1][j], min(dp[i][j - 1], dp[i - 1][j - 1])) + 1; } } } } int main() { IOS init(900010009); cin >> l[0] >> r[0] >> l[1] >> r[1]; solve(); cout << dp[m][n]; return 0; }
K、The score of the postgraduate re-examination
题意
共n个人,对于每个人:输入五个整数(0-100)和一个字符串(长度10以内)。
去掉一个最大值和一个最小值,剩余的数求平均数(下取整)。
问:平均分最高者,名字和分数分别是什么?若有多个相同,优先输出先输入的。
题解
思路1:排序
任意选择一种排序,排序后减去一个最大值和一个最小值即为总得分。由此,可得:
并且注意学生输入的顺序即可
时间复杂度:O(nlogn) 空间复杂度:O(n)
思路2:维护最值
一趟遍历维护出最大值
一趟遍历维护出最小值
一趟遍历维护处五个数总和
然后计算即可
时间复杂度:O(n) 空间复杂度:O(n)
代码实现
C++(思路1)
#include<iostream> #include<functional> #include<algorithm> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); using namespace std; int T; int a[5]; int ans_score; string ans_name; void solve() { int n = 5, res = 0; string name; for (int i = 0; i < n; ++ i) cin >> a[i]; cin >> name; make_heap(a, a + n, less<int>());//大根堆,第三个参数可以不写 do { pop_heap(a, a + n);//堆顶元素出堆,放在堆末,参数与make_heap一致 res += a[0];//取堆顶元素 } while (-- n > 2); if (ans_score < (res /= 3)) { ans_score = res; ans_name = name; } } int main() { IOS cin >> T; while (T --) { solve(); } cout << ans_score << ' ' << ans_name << '\n'; return 0; }
Java(思路2)
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scan = new Scanner(System.in); int n = scan.nextInt(); String name[] = new String[n]; Integer garde[][] = new Integer[n][5]; Integer ansMax = -1; Integer ansMaxLoc = 0; for(int i = 0; i < n; i++){ Integer min = 101; Integer minLoc = 0; Integer max = -1; Integer maxLoc = 0; for (int j = 0; j < 5; j++){ garde[i][j] = scan.nextInt(); if(garde[i][j] > max){ max = garde[i][j]; maxLoc = j; } if(garde[i][j] < min){ min = garde[i][j]; minLoc = j; } } name[i] = scan.next(); Integer cnt = 0; for(int j = 0; j < 5; j++){ if(j == maxLoc || j == minLoc) continue; cnt += garde[i][j]; } if((cnt / 3) > ansMax){ ansMax = cnt / 3; ansMaxLoc = i; } } System.out.println(ansMax + " " + name[ansMaxLoc]); } }
L、Ph0t05h0p
题意
交互题,共有以下四种操作:
- add
:增加一个名为str的图层 - modify
:修改第x个图层的名字为str,若不存在第x个图层,则操作无效 - list:打印出当前全部图层的名字,若不存在任何图层,输出“
” - undo:撤销上一步操作(仅add或modify),若不存在上一步操作,则操作无效
题解
用一个自定义栈
由于撤销的操作仅包含add和modify两种,因此可以用一个bool来表示操作的类型
维护一个bool类型的栈
撤销一个modify操作,不妨反向思考:如何将修改后的值改回原来的值?
假设第
想改回原来的值,只需要执行一次modify
因此,维护撤销modify操作,只需要用一个栈
list操作直接打印
时间复杂度:O(n) 空间复杂度:O(n)
代码实现
C++
#include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); using namespace std; int n, x; string op, str; vector<string> stk; stack<bool> un;//true代表"add"操作,false代表"modify"操作 stack<pair<int, string>> mo;//存储反向修改操作 void add() { cin >> str; stk.push_back(str); un.push(true);//记录add } void undo() { if (!un.empty()) { bool b = un.top(); un.pop(); if (b) { stk.pop_back(); } else { pair<int, string> p = mo.top(); mo.pop(); stk[p.first] = p.second; } } } void show() { if (stk.empty()) { cout << "empty" << endl; } else { for (auto &it: stk) { cout << it << ' '; } cout << endl; } } void modify() { cin >> x >> str; if (stk.size() <= x || x < 0) return ;//x不在合法范围内 mo.push(make_pair(x, stk[x]));//记录反向修改操作 stk[x] = str;//修改 un.push(false);//记录modify } int main() { IOS cin >> n; while (n --) { cin >> op; if (op[0] == 'a') { add(); } else if (op[0] == 'u') { undo(); } else if (op[0] == 'l') { show(); } else { modify(); } } return 0; }
M、Genshin Impact
题意
输出“I want to play the Genshin Impact!!!”
题解
整活题,hello world即可
时间复杂度:O(1) 空间复杂度:O(1)
代码实现
C++
#include <iostream> using namespace std; int main(){ cout << "I want to play the Genshin Impact!!!" << endl; return 0; }
Python 3
print("I want to play the Genshin Impact!!!")
总结
本场比赛侧重数据结构与算法的基础知识的考察,拟定
从比赛结果看,大部分选手表现出色,展示了扎实的编程基础和较强的解决问题能力。然而,也有部分选手在某些题目上遇到困难。希望各位选手赛后好好复盘,查缺补漏,再接再厉!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 本地部署 DeepSeek:小白也能轻松搞定!
· 如何给本地部署的DeepSeek投喂数据,让他更懂你
· 从 Windows Forms 到微服务的经验教训
· 李飞飞的50美金比肩DeepSeek把CEO忽悠瘸了,倒霉的却是程序员
· 超详细,DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方Dee