2023 睿抗机器人开发者大赛CAIP-编程技能赛-本科组(省赛) 解题报告 | 珂学家


前言

在这里插入图片描述


题解

2023 睿抗机器人开发者大赛CAIP-编程技能赛-本科组(省赛) 。

第3题是真的有意思,差点想当数学题做了。

第5题出得也好,非常思维的一道题。

在这里插入图片描述


RC-u1 亚运奖牌榜

分值: 10分

题型; 模拟

这边有个技巧,vector天然支持大小比较。

#include <bits/stdc++.h>

using namespace std;

int main() {

    int n;
    cin >> n;

    vector<vector<int>> cards(2, vector<int>(3));
    for (int i = 0; i < n; i++) {
        int c, p;
        cin >> c >> p;
        cards[c][p - 1]++;
    }

    cout << cards[0][0] << " " << cards[0][1] << " " << cards[0][2] << "\n";
    cout << cards[1][0] << " " << cards[1][1] << " " << cards[1][2] << "\n";
    
    // 向量直接比较
    if (cards[0] > cards[1]) {
        cout << "The first win!\n";
    } else {
        cout << "The second win!\n";
    }

    return 0;
}

RC-u2 出院

分值: 15分

考察: stl容器的使用,模拟

#include <bits/stdc++.h>

using namespace std;

int main() {

    int n, m;
    cin >> n >> m;
    map<string, string> hp;
    for (int i = 0; i < n; i++) {
        string name, tag;
        cin >> name >> tag;
        hp[name] = tag;
    }

    for (int i = 0; i < m; i++) {
        string s;
        cin >> s;
        int len = s.size();
        if (hp.count(s) > 0) {
            cout << hp[s] << "\n";
            continue;
        }

        string ans = "";
        int hits = 0;
        for (int j = 0; j < len - 1; j++) {
            string k1 = s.substr(0, j + 1);
            string k2 = s.substr(j + 1);
            if (hp.count(k1) > 0 && hp.count(k2) > 0) {
                ans = hp[k1] + hp[k2];
                hits++;
            }
        }
        if (hits == 1) {
            cout << ans << '\n';
        } else {
            cout << "D\n";
        }
    }

    return 0;
}

RC-u3 骰子游戏

分值: 20分

题型: 二进制枚举 + 暴力枚举 + 模拟

这题的码量其实特别大

  1. 编写光骰子获胜等级判定
  2. 二进制枚举,用于枚举需要变动的个数
  3. 确定重置的骰子后,暴力枚举可能的结果

胜率提升,需要保证改变后等级大于之前

如果能理顺这边的逻辑,那恭喜你,这题基本搞定。

总的时间复杂度为 O(25∗65∗6)O(2^5 * 6^5 * 6)O(25656)

#include <bits/stdc++.h>

using namespace std;

int judge(vector<int> &arr) {
    int hash[7] = {0};
    for (int &x: arr) hash[x]++;

    int cnt3 = 0, cnt2 = 0;
    for (int i = 1; i <= 6; i++) {
        if (hash[i] == 5) return 8;
        if (hash[i] == 4) return 7;
        if (hash[i] == 3) cnt3++;
        if (hash[i] == 2) cnt2++;
    }

    if (cnt3 == 1 && cnt2 == 1) return 6;

    if (hash[2] == 1 && hash[3] == 1 && hash[4] == 1 && hash[5] == 1 && hash[6] == 1) {
        return 5;
    }
    if (hash[2] == 1 && hash[3] == 1 && hash[4] == 1 && hash[5] == 1 && hash[1] == 1) {
        return 4;
    }

    if (cnt3 == 1) return 3;
    if (cnt2 == 2) return 2;
    if (cnt2 == 1) return 1;
    return 0;
}

int dfs(vector<int> &arr, int s, int id, int mask) {
    if (s == 5) {
        return judge(arr) > id ? 1 : 0;
    }
    int acc = 0;
    if (((1 << s) & mask) != 0) {
        int old = arr[s];
        for (int i = 1; i<= 6; i++) {
            arr[s] = i;
            acc += dfs(arr, s + 1, id, mask);
        }
        arr[s] = old;
    } else {
        acc += dfs(arr, s + 1, id, mask);
    }
    return acc;
}

int bitCount(int v) {
    int cnt = 0;
    while (v > 0) {
        v = v & (v - 1);
        cnt++;
    }
    return cnt;
}

int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}

int main() {
    int t;
    cin >> t;
    int times[] = {0, 6, 6 * 6, 6 * 6 * 6, 
        6 * 6 * 6 * 6, 
        6 * 6 * 6 * 6 * 6,
                   6 * 6 * 6 * 6 * 6 * 6};
    for (int i = 0; i < t; i++) {
        vector<int> arr(5);
        for (int &x: arr) cin >> x;

        // 判定牌的类型
        int id = judge(arr);
        
        // 进行暴力全枚举

        int ans = 0;
        int fz = 0, mz = 1;
        
        int mask = 1 << 5;
        for (int j = 1; j < mask; j++) {
            vector<int> brr(arr.begin(), arr.end());

            int change = bitCount(j);
            
            int fz2 = dfs(brr, 0, id, j);
            int mz2 = times[change];

            if (fz * mz2 < fz2 * mz || (fz * mz2 == fz2 * mz && ans > change)) {
                ans = change;
                fz = fz2;
                mz = mz2;
                int g = gcd(fz, mz);
                fz /= g;
                mz /= g;
            }
        }

        cout << ans << " " << fz << " " << mz << '\n';
        
    }
    return 0;
}

RC-u4 相对论大师

分值: 25分

考察:图论 + bfs

这题的关键就是图由m个节点n条边构成, n≤1000n \le 1000n1000

图的节点,由 论点 和 值 这个二元组构成

因为是稀疏图,遍历每个节点,进行bfs即可。

这样总的时间复杂度为 O(n∗m)O(n*m)O(nm)

不过写起来确实变扭

#include <bits/stdc++.h>

using namespace std;

struct K {
   string k; int v;
    K(string k, int v): k(k), v(v) {}
    bool operator<(const K& lhs) const {
        if (k != lhs.k) return k < lhs.k;
        return v < lhs.v;
    }
};

int id = 0;
map<K, int> mp;

int ide(K &e) {
    if (mp.find(e) != mp.end()) return mp[e];
    mp[e] = id++;
    return mp[e];
}

int main() {
    int n;
    cin >> n;

    vector<vector<int>> g;
    vector<K> vec;

    for (int i = 0; i < n; i++) {
        string k1; int v1;
        string k2; int v2;
        cin >> k1 >> v1 >> k2 >> v2;
        K e1(k1, v1), e2(k2, v2);

        int id1 = ide(e1);
        int id2 = ide(e2);
        if (id1 >= vec.size()) {
            vec.push_back(e1);
            g.push_back(vector<int>());
        }
        if (id2 >= vec.size()) {
            vec.push_back(e2);
            g.push_back(vector<int>());
        }

        g[id1].push_back(id2);
    }
    
    
    vector<int> bestAns;
    string startK = "";
    int startV = -1;
    
    int m = vec.size();
    for (int i = 0; i < m; i++) {
        int fe = -1;
        for (int j = 0; j < m; j++) {
            if (vec[i].k == vec[j].k && vec[i].v != vec[j].v) {
                fe = j;
                break;
            }
        }
        if (fe == -1) continue;
        
        int s = i;
        int inf = 0x3f3f3f3f;
        vector<int> dp(id, inf);
        vector<int> source(id, -1);

        deque<int> que;
        que.push_back(s);
        dp[s] = 0;

        while (!que.empty()) {
            int u = que.front(); que.pop_front();
            for (int v: g[u]) {
                if (dp[v] > dp[u] + 1) {
                    dp[v] = dp[u] + 1;
                    source[v] = u;
                    que.push_back(v);
                }
            }
        }
        if (source[fe] == -1) continue;

        int last = fe;
        vector<int> ans;
        while (source[last] != -1) {
            ans.push_back(last);
            last = source[last];
        }
        ans.push_back(last);
        
        if (startK == "" || bestAns.size() > ans.size()) {
            bestAns = ans;
            
            startK = vec[s].k;
            startV = vec[s].v;
        }
    }


    reverse(bestAns.begin(), bestAns.end());
    for (int i = 0; i < bestAns.size(); i++) {
        if (i > 1) {
            cout << vec[bestAns[i - 1]].k << " " << vec[bestAns[i - 1]].v << " ";
        }
        cout << vec[bestAns[i]].k << " " << vec[bestAns[i]].v << " ";
    }
    cout << "= " << startK << " " << startV << " " << startK << " " << (1 - startV) << "\n"
;    
    return 0;
}

RC-u5 相对成功与相对失败

分值: 30分

知识点: 思维 + 状态机DP

这题的核心是关系式,即

(1,0)>(1,1)∣(0,0)>(0,1) (1, 0) > (1, 1) | (0, 0) > (0, 1) (1,0)>(1,1)(0,0)>(0,1)

(1,1)和(0,0)(1,1) 和 (0,0)(1,1)(0,0) 没有偏序关系,可以合并为一种状态

那当前的序列中,其实就是划分为这3种状态,使得满足要求元素最多。

这里面有一种朴素的思路

3个状态,2个划分点,枚举2个划分点即可3个状态,2个划分点,枚举2个划分点即可3个状态,2个划分点,枚举2个划分点即可

但这个时间复杂度为O(n2),n≤105O(n^2), n \le 10^5O(n2),n105, 显然不行。

那如何求解呢?

可以引入状态机DP

令 s0, s1, s2分别为划分态的最优值

具体状态方程见代码, 整个时间复杂度为O(n)O(n)O(n)


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t-- > 0) {
        int n;
        cin >> n;

        vector<array<int, 2>> arr;
        for (int i = 0; i < n; i++) {
            int a, b;
            cin >> a >> b;
            arr.push_back({a, b});
        }
        vector<int> seq(n);
        for (int &x: seq) cin >> x;

        // 偏序关系
        // (1, 0) > (0, 0) | (1, 1) > (0, 1) 

        // 可以枚举分界点,但这样是O(n^2)
        // 试试 状态机DP

        int s0 = 0, s1 = 0, s2 = 0;
        for (int x: seq) {
            auto e = arr[x - 1];

            if (e[0] == 1 && e[1] == 0) {
                int t0 = s0 + 1;
                int t1 = max(s0, s1);
                int t2 = max({s0, s1, s2});
                s0 = t0; s1 = t1; s2 = t2;
            } else if (e[0] == 0 && e[1] == 1) {
                int t0 = s0;
                int t1 = max(s0, s1);
                int t2 = max({s0, s1, s2}) + 1;
                s0 = t0; s1 = t1; s2 = t2;
            } else {
                int t0 = s0;
                int t1 = max(s0, s1) + 1;
                int t2 = max({s0, s1, s2});
                s0 = t0; s1 = t1; s2 = t2;
            }
        }
        
        cout << n - max({s0, s1, s2}) << endl;
    }
    return 0;
}

写在最后

在这里插入图片描述

### 编程介绍 编程(RAICOM)是RoboCom机器人开发者大赛中的一个重要分支,专注于编程技能的竞与培养。该比旨在通过实际问题解决和算法设计,提升参者的编程能力、逻辑思维以及团队协作能力[^1]。比分为本科、专科等多个层次,并且覆盖国两个级别,为不同阶段的学习者提供了丰富的竞技平台。 比内容通常涉及但不限于以下领域: - **算法设计**:要求选手掌握基础算法如排序、搜索等,并能够灵活应用到复杂场景中。 - **数据结构**:树、图、堆栈等数据结构的应用是比的重要部分。 - **程序优化**:在限定时间内完成高效的代码编写,注重时间复杂度和空间复杂度的平衡。 此外,比还强调对实际问题的建模能力和解决方案的设计,这需要参者具备扎实的数学基础和编程实践经验[^2]。 --- ### 编程资源推荐 #### 1. 历年真题与解题报告 历年真题是备战编程的核心资源之一。通过研究往年的题目,可以了解比的出题风格和考察重点。例如,2023年和2024年的本科及专科真题及其详细解题报告已经公开,这些资料可以帮助参者熟悉比形式并积累解题经验[^3]。 #### 2. 学习平台 - **LeetCode** 和 **Codeforces**:这两个平台提供了大量高质量的算法题,适合日常练习和提高编程能力。 - **洛谷** 和 **牛客网**:国内知名在线评测系统,拥有丰富的题库和社区讨论区,适合初学者和进阶学习者。 #### 3. 技术文档与工具 - **C++ STL 容器类**:熟练掌握 STL 容器(如 vector、map、set 等)是高效编程的基础[^1]。 - **仿真软件 iLook**:在某些特定场景下,可能需要使用仿真软件进行调试。如果遇到权限问题,可以通过管理员权限的方式解决[^4]。 #### 4. 其他资源 - **PDF 资料**:包括编程笔记、常见算法题解以及知识点汇总等,适合打印后随身携带复习。 - **社区交流**:加入相关论坛或微信群,与其他参者分享经验和学习心得,有助于拓宽视野。 --- ```python # 示例代码:快速排序实现 def quick_sort(arr): if len(arr) <= 1: return arr else: pivot = arr[len(arr) // 2] left = [x for x in arr if x < pivot] middle = [x for x in arr if x == pivot] right = [x for x in arr if x > pivot] return quick_sort(left) + middle + quick_sort(right) ``` 上述代码展示了快速排序的基本实现方式,这是编程中常见的算法之一,值得深入理解并熟练掌握。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值