Hitachi Vantara Programming Contest 2024(AtCoder Beginner Contest 368)ABCDEF

前言

F比E简单多了,难评

A题:Cut

题意

给定n张卡片,将后m张卡片按顺序放置到顶部,按顺序输出卡片id

思路

更改输出方式即可

代码

cpp 复制代码
inline void solve() {
     int n, m; cin >> n >> m;
     vector<int> a(n + 1);
     for (int i = 1; i <= n; i ++ ) cin >> a[i];
     for (int i = n - m + 1; i <= n; i ++ ) cout << a[i] << ' ';
     for (int i = 1; i <= n - m; i ++ ) cout << a[i] << ' ';
	 return;
}

B题: Decrease 2 max elements

题意

对于一次操作,将整个数组降序sort一遍,并且将第一个和第二个元素的值减去一,问使得数组最多存在一个正整数的最小操作次数

思路

数据很小,并且是B题,不要多想,直接暴力

代码

cpp 复制代码
inline void solve() {
     int n; cin >> n;
     vector<int> a(n + 1);
     for (int i = 1; i <= n; i ++ ) cin >> a[i];
     sort(a.begin() + 1, a.end(), greater<>());
     int cnt = 0;
     while (a[2] > 0) {
        a[1] -= 1, a[2] -= 1;
        sort(a.begin() + 1, a.end(), greater<>());
        cnt += 1;
     }
     cout << cnt << endl;
	 return;
}

C题:Triple Attack

题意

有n名敌人,我们每次攻击最前面那一个,定义T一开始为0,每进行一次攻击,会使得T值加一,当T是3的倍数的时候,攻击伤害为3,否则为1。问击败所有敌人所需的T

思路

这肯定跟周期有关了,在周期5的条件下,我们一共可以攻击5滴血。这个可以直接用除和模进行计算。

然后会剩下%5后的血量,我们直接进行模拟即可

代码

cpp 复制代码
inline void solve() {
     int n; cin >> n;
     vector<int> a(n + 1);
     int cur = 1;
     ll ans = 0;
     for (int i = 1; i <= n; i ++ ) {
        int x; cin >> x;
        ans += x / 5 * 3;
        x %= 5;
        while (x) {
            int at = cur % 3 == 0 ? 3 : 1;
            int minv = min(at, x);
            x -= minv;
            cur += 1, ans += 1;
        }
     }
     cout << ans << endl;
	 return;
}

D题:Minimum Steiner Tree

题意

每次可以删去一个叶节点,问包含k个给定节点的最小树的大小是多少

思路

直接dfs,我们以一个给定的节点作为起点进行dfs,如果遇到了给定的节点,那么我们就要将这条路上的所有节点都进行"染色"(因为这些节点是到达此节点的必要条件)。最后输出染色的节点数量即可

代码

cpp 复制代码
inline void solve() {
     int n, k; cin >> n >> k;
     vector<vector<int>> e(n + 1);
     for (int i = 1; i < n; i ++ ) {
        int a, b; cin >> a >> b;
        e[a].push_back(b), e[b].push_back(a);
     }
     map<int, int> vis;
     int st;
     for (int i = 1; i <= k; i ++ ) {
        int x; cin >> x;
        vis[x] = 1;
        st = x;
     }
     int ans = 0;
     vector<int> used(n + 1);
     function<void(int, int, vector<int>&)> dfs = [&](int u, int pre, vector<int>& path) {
        if (vis[u]) {
            for (int i = path.size() - 1; i >= 0; i -- ) {
                if (!used[path[i]]) used[path[i]] = 1, ans += 1;
                else break;
            }
        }
        for (int v : e[u]) {
            if (v == pre) continue;
            path.push_back(v);
            dfs(v, u, path);
            path.pop_back();
        }
     };
     vector<int> p;
     p.push_back(st);
     dfs(st, -1, p);
     cout << ans << endl;
	 return;
}

E题:Train Delay

题意

建议直接看原题进行理解

思路

模拟

首先我们将时间sort一遍,然后进行遍历

对于遍历到的点,要将其前面所有到达时间小于等于其出发时间的点对目的地的最低下限进行更新

什么意思呢?

10 20 1 2

30 40 2 3

四个信息分别为出发时间,到达时间,起点,终点

我们注意到30>20,那么对于终点2来说,其下限时间为20+它的推迟时间

此后遍历到的2的点的出发时间都要大于等于20+它的推迟时间

这个过程可以用优先队列进行模拟

代码

cpp 复制代码
inline void solve() {
     int n, m, x; cin >> n >> m >> x;
     vector<ll> ans(m + 1);
     ans[1] = x;
     vector<array<int, 5>> p(m + 1);
     for (int i = 1; i <= m; i ++ ) {
        int a, b, s, t; cin >> a >> b >> s >> t;
        p[i] = {s, t, a, b, i};
     }
     sort(p.begin() + 1, p.end());
     using P = array<ll, 3>;
     priority_queue<P, vector<P>, greater<P>> q;
     vector<ll> d(n + 1);
     for (int i = 1; i <= m; i ++ ) {
        auto [s, t, a, b, id] = p[i];
        while (q.size() && q.top()[0] <= s) {
            auto [t1, t2, pos] = q.top();
            q.pop();
            d[pos] = max(d[pos], t2);
        }
        ans[id] = max(ans[id], d[a] - s);
        q.push({t, t + ans[id], b});
     }
     for (int i = 2; i <= m; i ++ ) cout << ans[i] << ' ';
	 return;
}

F题:Dividing Game

题意

见题目

思路

像,太像了。之前cf上也做过一道sg函数的,不过那个是猜的,这个可以明显计算

因为它进行的改变是将x变成小于其的任意正因数

所以我们预处理1e5的sg函数的时候,复杂度为1e5*sqrt(a)

这就直接处理出来了,秒了,比E简单100倍

你可能会注意到,下面用了一个while求sg函数

因为我打表前1000个,它的sg值就没有超过10,所以可以直接while遍历

代码

cpp 复制代码
const int N = 1e5 + 9;
int sg[N];
inline void solve() {
     int n; cin >> n;
     int ans = 0;
     for (int i = 1; i <= n; i ++ ) {
        int x; cin >> x;
        ans ^= sg[x];
     }
     cout << (ans ? "Anna" : "Bruno") << endl;
	 return;
}

inline void pre_work() {
    sg[1] = 0;
	for (int i = 2; i <= 100000; i ++ ) {
        set<int> s;
        s.insert(0);
        for (int j = 2; j * j <= i; j ++ ) {
            if (i % j == 0) {
                s.insert(sg[j]);
                s.insert(sg[i / j]);
            }
        }
        int cur = 0;
        while (true) {
            if (!s.count(cur)) {
                sg[i] = cur;
                break;
            }
            cur += 1;
        }
    }
}
相关推荐
盼海15 分钟前
排序算法(五)--归并排序
数据结构·算法·排序算法
网易独家音乐人Mike Zhou4 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
搬砖的小码农_Sky6 小时前
C语言:数组
c语言·数据结构
Swift社区7 小时前
LeetCode - #139 单词拆分
算法·leetcode·职场和发展
Kent_J_Truman8 小时前
greater<>() 、less<>()及运算符 < 重载在排序和堆中的使用
算法
先鱼鲨生8 小时前
数据结构——栈、队列
数据结构
一念之坤8 小时前
零基础学Python之数据结构 -- 01篇
数据结构·python
IT 青年8 小时前
数据结构 (1)基本概念和术语
数据结构·算法
熬夜学编程的小王8 小时前
【初阶数据结构篇】双向链表的实现(赋源码)
数据结构·c++·链表·双向链表
Dong雨9 小时前
力扣hot100-->栈/单调栈
算法·leetcode·职场和发展