2024 年 GPLT 团体程序设计天梯赛 - 全国总决赛

考试题倒不是有多难,就是需要注意的细节有很多。我的总分是 218,二等奖擦边过~算是运气比较好吧。

考试的时候手机(第二机位)没电关机了,但是老师没管哈哈哈。。。

点击下面的题目标题跳转到对应题目链接~🫢

L1-1 编程解决一切

考察:简单输出

解题思路

语言选择 Python → 鼠标放到输出样例最右端一键赋值 → 提交(5s 解决)

代码

print('Problem? The Solution: Programming.')

L1-2 再进去几个人

考察:简单输入输出

解题思路

这道题代码很少,就是读题可能稍微花点时间,但也能 2 分钟内解决。

代码

a, b = map(int, input().split())
print(b - a)

L1-3 帮助色盲

考察:模拟

解题思路

按照题目中的要求一点一点写就行。

代码

a, b = map(int, input().split())
if a <= 1:
    if b: print('-')
    else: print('dudu' if a else 'biii')
else: print('-')
print('move' if a == 1 else 'stop')

L1-4 四项全能

考察:简单数学

解题思路

假设所有人会 m - 1 种技能点,多出的技能点的数量就是要求的人数。

注意技能点总数有可能不足 n * (m - 1),这时输出 0

代码

n, m = map(int, input().split())
print(max(0, sum(map(int, input().split())) - n * (m - 1)))

L1-5 别再来这么多猫娘了

考察:简单字符串查找

解题思路

注意题目中的关键信息:“从左到右处理文本违禁词则按照输入顺序依次处理;对于有重叠的情况,无论计数还是替换,查找完成后从违禁词末尾继续处理。”

然后模拟上述操作即可。但是我只能得 10 分,不知道为啥。

代码

n = int(input())
banned = [input() for _ in range(n)]
k, c = int(input()), 0
s = input()

i, res = 0, ''
while i < len(s):
    for b in banned:
        if s[i:i + len(b)] == b:
            c += 1
            i += len(b)
            res += '<censored>'
            break
    else:
        res += s[i]
        i += 1

print(res if c < k else f'{c}\nHe Xie Ni Quan jia!')

L1-6 兰州牛肉面

考察:语法

解题思路

用一个 cnt 数组保存每种牛肉面的购买次数,用 total 累加总销售额。

代码

cin = lambda t=int: list(map(t, input().split()))

n = int(input())
prices = cin(float)
cnt, total = [0] * n, 0

while True:
    t, num = cin()
    if not t: break
    cnt[t - 1] += num
    total += prices[t - 1] * num

for c in cnt:
    print(c)
print('%.2f' % total)

L1-7 整数的持续性

考察:模拟

解题思路

L1 一般对时间复杂度没有要求,所以直接模拟就行。

代码

a, b = map(int, input().split())

def calc(x):
    res = 0
    while len(str(x)) > 1:
        t = 1
        while x:
            t *= x % 10
            x //= 10
        x = t
        res += 1
    return res

mx, ans = 0, []
for i in range(a, b + 1):
    t = calc(i)
    if t > mx: mx, ans = t, [i]
    elif t == mx: ans.append(i)

print(mx)
print(' '.join(str(i) for i in ans))

L1-8 九宫格

考察:模拟简单思维

解题思路

用三个数组保存每一行、每一列、每个九宫格中每个数的出现情况。如果1~9中有数字出现多次,或者出现范围外的数字,就把 flag 设为 false。

代码

for _ in range(int(input())):
    m = [list(map(int, input().split())) for _ in range(9)]
    r, c, v = [[[0] * 10 for _ in range(9)] for _ in range(3)]
    flag = False
    for i in range(9):
        for j in range(9):
            if m[i][j] <= 0 or m[i][j] > 9 or r[i][m[i][j]] or c[j][m[i][j]] or v[i // 3 * 3 + j // 3][m[i][j]]:
                flag = True
                break
            r[i][m[i][j]] = c[j][m[i][j]] = v[i // 3 * 3 + j // 3][m[i][j]] = 1
        if flag: break
    print(0 if flag else 1)

L2-1 鱼与熊掌

考察:平衡树

解题思路

用 set 来记录每种商品的购买者。然后在多个集合中找交集即可。

注意为了不让最后一个点超时,要加一个小优化:遍历较小的集合。

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;
int n, m;
set<int> M[N];

int main() {
    cin.tie(0) -> sync_with_stdio(false);
    cin >> n >> m;
    for (int i = 1, k; i <= n; i++) {
        cin >> k;
        while (k--) {
            int x; cin >> x;
            M[x].insert(i);
        }
    }
    int q; cin >> q;
    while (q--) {
        int x, y, res = 0;
        cin >> x >> y;
        if (M[x].size() <= M[y].size())
            for (int i : M[x])
                res += M[y].count(i);
        else
            for (int i : M[y])
                res += M[x].count(i);
        cout << res << endl;
    }
    return 0;
}

L2-2 懂蛇语

考察:哈希表

解题思路

注意输入的单词中可能会有多个空格,开头也有可能有空格。

注意整行输入前要用 cin.ignore() 或者 getchar() 来忽视掉换行符。

用 C++ 的 stringstream 可以很好的处理这种输入。

代码

#include <bits/stdc++.h>
using namespace std;

unordered_map<string, vector<string>> mp;

string trans(string& line) {
    string ans, t;
    stringstream ss(line);
    while (ss >> t)
        ans += t[0];
    return ans;
}

int main() {
    int n, m;
    cin >> n; cin.ignore();
    while (n--) {
        string line;
        getline(cin, line);
        mp[trans(line)].emplace_back(line);
    }
    for (auto& [k, v] : mp)
        sort(v.begin(), v.end());
    cin >> m; cin.ignore();
    while (m--) {
        string line;
        getline(cin, line);
        string res = trans(line);
        if (mp.count(res)) {
            int sz = mp[res].size();
            for (int i = 0; i < sz; i++)
                cout << mp[res][i] << "|\n"[i == sz - 1];
        } else cout << line << endl;
    }
    return 0;
}

L2-3 满树的遍历

考察:DFS

解题思路

树的前序遍历没啥好说的。用一个变量保存每个节点的度,判断是不是满树。

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;
int n, m, f[N], rt, k;
vector<int> e[N], pre;

bool dfs(int u) {
    if (e[u].empty())
        return true;
    if (k != e[u].size())
        return false;
    k = max(k, (int)e[u].size());
    for (int& v : e[u])
        if (!dfs(v))
            return false;
    return true;
}

void preorder(int u) {
    pre.emplace_back(u);
    sort(e[u].begin(), e[u].end());
    for (int& v : e[u])
        preorder(v);
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> f[i];
        if (!f[i]) rt = i;
        e[f[i]].emplace_back(i);
    }
    k = e[rt].size();
    bool res = dfs(rt);
    cout << k << ' ' << (res ? "yes" : "no") << endl;
    preorder(rt);
    for (int i = 0; i < n; i++)
        cout << pre[i] << " \n"[i == n - 1];
    return 0;
}

L2-4 吉利矩阵

考察:回溯

解题思路

在一个二维矩阵内回溯,用 r 和 c 数组分别保存每一行、每一列列的总和,注意细节和边界情况即可。

代码

#include <bits/stdc++.h>
using namespace std;

int l, n, res, r[4], c[4];

void add(int i, int j, int x) {
    r[i] += x;
    c[j] += x;
}

void rm(int i, int j, int x) {
    r[i] -= x;
    c[j] -= x;
}

void dfs(int i, int j) {
    if (i == n - 1 && j != n - 1) {
        int x = l - c[j];
        add(i, j, x);
        if (r[i] <= l && c[i] <= l)
            dfs(i, j + 1);
        rm(i, j, x);
        return;
    }
    if (j == n - 1 && i != n - 1) {
        int x = l - r[i];
        add(i, j, x);
        if (r[i] <= l && c[i] <= l)
            dfs(i + 1, 0);
        rm(i, j, x);
        return;
    }
    if (i == n - 1 && j == n - 1) {
        res += r[i] == c[j];
        return;
    }
    for (int x = 0; x <= l - max(r[i], c[j]); x++) {
        add(i, j, x);
        dfs(i, j + 1);
        rm(i, j, x);
    }
}

int main() {
    cin >> l >> n;
    dfs(0, 0);
    cout << res;
    return 0;
}

L3-1 夺宝大赛

考察:BFS

解题思路

用多个数组记录多个节点的遍历情况。但是最后一个点超时了,求大佬赐教!

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 105, nxt[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
int m, n, a[N][N], tx, ty;
bool vis[N * N / 2][N][N];
queue<tuple<int, int, int>> q;
vector<int> winner;

int main() {
    cin >> m >> n;
    for (int i = 1; i <= m; i++)
        for (int j = 1; j <= n; j++) {
            cin >> a[i][j];
            if (a[i][j] == 2)
                tx = i, ty = j;
        }
    int k; cin >> k;
    for (int i = 1; i <= k; i++) {
        int x, y;
        cin >> y >> x;
        vis[i][x][y] = true;
        q.push({x, y, i});
    }
    int t = 0;
    while (q.size()) {
        int sz = q.size();
        while (sz--) {
            auto [x, y, id] = q.front(); q.pop();
            if (x == tx && y == ty) {
                winner.emplace_back(id);
                continue;
            }
            for (int i = 0; i < 4; i++) {
                int nx = x + nxt[i][0], ny = y + nxt[i][1];
                if (0 < nx && nx <= m && 0 < ny && ny <= n && a[nx][ny] && !vis[id][nx][ny]) {
                    vis[id][nx][ny] = true;
                    q.push({nx, ny, id});
                }
            }
        }
        if (winner.size()) {
            if (winner.size() > 1) winner.clear();
            else {
                cout << winner[0] << ' ' << t;
                return 0;
            }
        }
        t++;
    }
    cout << "No winner.";
    return 0;
}

最后

有什么问题欢迎在评论区讨论交流!

  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南宫谨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值