牛客小白月赛74 补题记录(D E F)

文章包含三道编程竞赛题目(D-修改后的和,E-幼稚园的树2,F-最便宜的构建)的解题思路和C++代码实现,主要涉及数组处理、排序、条件判断以及最优化策略。D题通过排序选取最大贡献元素,E题考虑不同情况计算满足条件的值,F题利用二分查找和并查集判断连通性。
摘要由CSDN通过智能技术生成

目录

前言:

正文:

D-修改后的和_牛客小白月赛74 (nowcoder.com)

思路:

代码:

E-幼稚园的树2_牛客小白月赛74 (nowcoder.com)

思路:

代码:

F-最便宜的构建_牛客小白月赛74 (nowcoder.com)

思路:

代码:


前言:

主要是存一下代码,因为时间紧,所以没仔细解析。

正文:

D-修改后的和_牛客小白月赛74 (nowcoder.com)

思路:

vec存放贡献大于0的,按贡献进行排序,取能取的前min(m,vec.size())个即可

代码:

#include <bits/stdc++.h>

using namespace std;
using i64 = long long;

void solve() {
    int n, m;
    cin >> n >> m;

    vector<int> vec; // vec:存放贡献大于0的下标
    vector<i64> a(n), can(n); // can:存放贡献
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        can[i] = max(0LL, 1LL * a[i] * (n - i));
        if (can[i] > 0) {
            vec.push_back(i);
        }
    }

    sort(vec.begin(), vec.end(), [&](int x, int y){
        return can[x] > can[y];
    });

    i64 ans = accumulate(a.begin(), a.end(), 0LL); // 注意使用这个函数long long时候需要0LL !!!
    for (int i = 0; i < min(int(vec.size()), m); i++) {
        ans -= can[vec[i]];
    }
    cout << ans << "\n";
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t;
    cin >> t;

    while (t--) {
        solve();
    }

    return 0;
}

E-幼稚园的树2_牛客小白月赛74 (nowcoder.com)

思路:

分情况搞一下就行,当时没过是因为没注意到即使整除也只能到下一天这个事

代码:

#include <bits/stdc++.h>

using namespace std;
using i64 = long long;

constexpr int N = 2e5 + 10;
i64 a[N], h[N], ans[N];
i64 fir, sec;
int n, m, k, b;

void solve() {
    cin >> n >> m >> k >> b;

    for (int i = 1; i <= n; i++) {
        cin >> h[i];
    }

    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        if (h[i] + (m - 1) * a[i] <= k) { // 永远达不到k
            ans[i] = h[i] + (m - 1) * a[i];
        } else { // 达到k后反复清除
            i64 fir = (k - h[i]) / a[i] + 1; // 这里不是 + a[i] -1上取整这种做法,而是直接+1,因为即使整除也只能在下一天
            i64 sec = (k - b) / a[i] + 1;
            int lev = (m - 1) - fir;
            lev %= sec;
            ans[i] = b + lev * a[i];
        }
    }
    for (int i = 1; i <= n; i++) {
        cout << ans[i] << " \n"[i == n];
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t;
    cin >> t;

    while (t--) {
        solve();
    }

    return 0;
}

F-最便宜的构建_牛客小白月赛74 (nowcoder.com)

思路:

二分答案,二分边权最大值最小,使用并查集检验点集的连通性即可

代码:

#include <bits/stdc++.h>

using namespace std;
using i64 = long long;

struct DSU {
    std::vector<int> p, siz;
    DSU(int n) : p(n + 1), siz(n + 1, 1) {
        std::iota(p.begin(), p.end(), 0);
    }

    int find(int x) {
        return p[x] == x ? x : p[x] = find(p[x]);
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }

    bool merge(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) {
            return false;
        }
        siz[x] += siz[y];
        p[y] = x;
        return true;
    }

    int size(int x) {
        return siz[find(x)];
    }
};

struct edge {
    int u, v, w;
};

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

	int n, m;
    cin >> n >> m;
	
	vector<edge> vec(m);
    for (int i = 0; i < m; i++) {
        cin >> vec[i].u >> vec[i].v >> vec[i].w;
    }

    sort(vec.begin(), vec.end(), [&](const edge &A, const edge &B){
        return A.w < B.w;
    });

	int k;
    cin >> k;
	
	vector<int> vertex[k];
    for (int i = 0; i < k; i++) {
        int s;
        cin >> s;
		vertex[i].resize(s);
        for (int j = 0; j < s; j++) {
			cin >> vertex[i][j];
		}
    }
    
	auto check = [&](int x) {
        DSU dsu(n); 
        for (int i = 0; i < m; i++) {
            if (vec[i].w > x) {
                break;
            }
            dsu.merge(vec[i].u, vec[i].v);
        }
        for (int i = 0; i < k; i++) {
            for (int j = 0; j < vertex[i].size(); j++) {
                if (dsu.find(vertex[i][j]) != dsu.find(vertex[i][0])) {
                    return false;
                }
            }
        }      
        return true;
    };

    int l = 1, r = 1E9; 
    while (l < r) {
        int mid = l + r >> 1;
        if (check(mid)) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }

    cout << l << "\n";

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值