AcWing第2周周赛题解

A. AcWing 3626. 三元一次方程

题目链接:https://www.acwing.com/problem/content/3629/

题目大意:求出三元一次方程 \(3x+5y+7z=n\) 的一组非负整数解。

解题思路:枚举 \(x\)\(y\)

示例程序:

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

int T, n;

void solve() {
    for (int x = 0; 3*x <= n; x++) {
        for (int y = 0; 3*x+5*y <= n; y++) {
            if ((n - 3*x - 5*y) % 7 == 0) {
                int z = (n - 3 * x - 5 * y) / 7;
                cout << x << " " << y << " " << z << endl;
                return;
            }
        }
    }
    cout << -1 << endl;
}

int main() {
    cin >> T;
    while (T--) {
        cin >> n;
        solve();
    }
    return 0;
}

B. AcWing 3627. 最大差值

题目链接:https://www.acwing.com/problem/content/3630/

题目大意:给定一个数列。每次操作选择两个非 0 的元素 ai 和 aj,然后选择一个整数 c(0≤c≤ai),使得 ai 减少 c,aj 增加 c。问,在操作全部完成后,序列中的最大值和最小值之差是多少。

解题思路:贪心。数列中最小的数只能变为 \(0\),每次选择最大的两个数(设为 \(a_i\)\(a_j\))满足 \(a_i \le a_j\),然后将 \(a_i\) 减去 \(a_i\)(变为 \(0\)),将 \(a_j\) 加上 \(a_i\)(变为 \(a_j + a_i\))。具体实现时我准备用优先队列实现。

示例程序:

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

priority_queue<long long> que;
int T, n, k;
long long a, b;

int main() {
    cin >> T;
    while (T--) {
        while (!que.empty()) que.pop();
        cin >> n >> k;
        while (n--) {
            cin >> a;
            que.push(a);
        }
        while (k--) {
            a = que.top();
            que.pop();
            b = que.top();
            que.pop();
            que.push(a+b);
        }
        cout << que.top() << endl;
    }
    return 0;
}

C. AcWing 3628. 边的删减

题目链接:https://www.acwing.com/problem/content/description/3631/

题目大意:最多保留 \(k\) 条边,使剩下的图中与节点 \(1\) 的最短距离等于之前的图中的最短距离的点的数量尽可能地大,求保留了哪些边。

解题思路:

  • 先求最短路(我用的spfa)
  • 然后bfs一遍,如果节点 \(1\)\(u\) 的最短路径长度加上 \(u\)\(v\) 的长度等于节点 \(1\)\(v\) 的最短路径长度,则算入这条边,同时 \(v\) 入队。

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int n, m, k;
long long dis[maxn];
bool inq[maxn], ok[maxn], vis[maxn];
queue<int> que;
struct Edge { int v, w, id; };
vector<Edge> g[maxn];

void spfa() {
    memset(dis, -1, sizeof(dis));
    dis[1] = 0;
    que.push(1);
    while (!que.empty()) {
        int u = que.front(); que.pop(); inq[u] = false;
        for (auto e : g[u]) {
            int v = e.v, w = e.w;
            if (dis[v] == -1 || dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                if (!inq[v]) {
                    inq[v] = true;
                    que.push(v);
                }
            }
        }
    }
}

void bfs() {
    int cnt = 0; // cnt 表示保留的边的数量
    vis[1] = true;
    while (!que.empty()) que.pop();
    que.push(1);
    while (!que.empty() && k > 0) {
        int u = que.front();
        que.pop();
        for (auto e : g[u]) {
            int v = e.v, w = e.w;
            if (!vis[v] && dis[u] + w == dis[v] && k > 0) {
                vis[v] = true;
                ok[e.id] = true;
                k --;
                cnt++;
                que.push(v);
            }
        }
    }
    cout << cnt << endl;
    for (int i = 1; i <= m; i++)
        if (ok[i])
            cout << i << " ";
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    cin >> n >> m >> k;
    for (int i = 1; i <= m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        g[u].push_back({v, w, i});
        g[v].push_back({u, w, i});
    }
    spfa();
    bfs();
    return 0;
}
posted @ 2022-04-07 10:49  quanjun  阅读(29)  评论(0编辑  收藏  举报