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;
        }
    }
}
相关推荐
XH华15 分钟前
初识C语言之二维数组(下)
c语言·算法
南宫生37 分钟前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
不想当程序猿_1 小时前
【蓝桥杯每日一题】求和——前缀和
算法·前缀和·蓝桥杯
落魄君子1 小时前
GA-BP分类-遗传算法(Genetic Algorithm)和反向传播算法(Backpropagation)
算法·分类·数据挖掘
菜鸡中的奋斗鸡→挣扎鸡1 小时前
滑动窗口 + 算法复习
数据结构·算法
Lenyiin1 小时前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
郭wes代码1 小时前
Cmd命令大全(万字详细版)
python·算法·小程序
scan7242 小时前
LILAC采样算法
人工智能·算法·机器学习
菌菌的快乐生活2 小时前
理解支持向量机
算法·机器学习·支持向量机
大山同学2 小时前
第三章线性判别函数(二)
线性代数·算法·机器学习