ICPC 2023 山东省赛

A. Orders

题目大意

n个订单,要求在\(a_i\)天的时候交付\(b_i\)个产品,每天能生产k个,问能否完成所有订单

解题思路

统计交付日期对应的产品数量,模拟计算剩余产品数量看中途是否会有无法交付的情况即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int tt;
    std::cin >> tt;

    while (tt--) {
        i64 n, k, cnt = 0, last = 0;
        std::cin >> n >> k;

        std::map<i64, i64> mp;
        for (int i = 0; i < n; i++) {
            i64 a, b;
            std::cin >> a >> b;
            mp[a] += b;
        }

        for (auto [a, b] : mp) {
            cnt += (a - last) * k - b;
            if (cnt < 0) {
                std::cout << "No\n";
                break;
            }
            last = a;
        }
        if (cnt >= 0) {
            std::cout << "Yes\n";
        }
    }
}

I. Three Dice

题目大意

三个六面的筛子,红点数为1和4,剩余为黑点数,问能否投出红点数为a,黑点数为b的组合

解题思路

暴力枚举即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int a, b;
    std::cin >> a >> b;

    for (auto a1 : {0, 1, 4}) {
        for (auto a2 : {0, 1, 4}) {
            for (auto a3 : {0, 1, 4}) {
                for (auto b1 : {0, 2, 3, 5, 6}) {
                    for (auto b2 : {0, 2, 3, 5, 6}) {
                        for (auto b3 : {0, 2, 3, 5, 6}) {
                            if ((int)(a1 == 0) + (int)(a2 == 0) + (int)(a3 == 0) + (int)(b1 == 0) + (int)(b2 == 0) + (int)(b3 == 0) == 3 && a1 + a2 + a3 == a && b1 + b2 + b3 == b) {
                                std::cout << "Yes\n";
                                return 0;
                            }
                        }
                    }
                }
            }
        }
    }
    std::cout << "No\n";
}

G. Matching

题目大意

给定一个数组,如果\(i-j=a_i-a_j\)则对ij连边,边权为两数之和,找最大的边权和

解题思路

条件的意思就是所有的\(a_i-i\)联通,因为要取最大所以降序匹配最大的正数即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int tt;
    std::cin >> tt;

    while (tt--) {
        int n;
        std::cin >> n;

        std::map<i64, std::priority_queue<i64>> mp;
        for (int i = 0; i < n; i++) {
            i64 x;
            std::cin >> x;
            mp[x - i].emplace(x);
        }

        i64 ans = 0;
        for (auto [x, y] : mp) {
            while (y.size() >= 2) {
                auto aa = y.top();
                y.pop();
                auto bb = y.top();
                y.pop();
                if (aa + bb > 0) {
                    ans += aa + bb;
                } else {
                    break;
                }
            }
        }

        std::cout << ans << "\n";
    }
}

D. Fast and Fat

题目大意

队伍有n个人,每个人有速度\(v_i\)和体重\(w_i\),每个人可以带上至多一个人行动,a如果带上b则两人的速度会都变为\(v_a - max(w_b - w_a, 0)\),被带上的人不能再带其他人行动,队伍中速度最慢的人就是整个队伍的速度,问最慢的速度最快是多少

解题思路

二分队伍的速度x,然后考虑check,如果第i个人的速度大于x,则他可以带上\(w_i+v_i-x\)的人,否则就需要被别人带,对速度降序贪心即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int tt;
    std::cin >> tt;

    while (tt--) {
        int n;
        std::cin >> n;

        std::vector<std::array<i64, 2>> vw(n);
        for (int i = 0; i < n; i++) {
            std::cin >> vw[i][0] >> vw[i][1];
        }
        std::sort(vw.begin(), vw.end(), std::greater<>());

        auto check = [&](int x) -> bool {
            std::multiset<i64> mst;
            for (auto [v, w] : vw) {
                if (v >= x) {
                    mst.insert(w + v - x);
                } else {
                    auto pos = mst.lower_bound(w);
                    if (pos != mst.end()) {
                        mst.erase(pos);
                    } else {
                        return false;
                    }
                }
            }
            return true;
        };

        int l = 1, r = 1e9 + 10;
        while (l <= r) {
            int mid = (l + r) >> 1;
            if (check(mid)) {
                l = mid + 1;
            } else {
                r = mid - 1;
            }
        }
  
        std::cout << r << "\n";
    }
}

L. Puzzle: Sashigane

题目大意

给定n*n的矩阵,除了指定位置外都要用L型(图形的样子可以自定义)来填充,要求用不超过\(\frac{n^2-1}{3}\)个图形完成填充,输出填充方案

解题思路

根据指定的位置可以知道其上下左右要填充多少格,然后对于lr,ud方向取大填充对应长度即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int n, i, j;
    std::cin >> n >> i >> j;
    int l = j - 1, r = n - j, u = i - 1, d = n - i;
    std::vector<std::array<int, 4>> ans;
    while (std::max({l, r, u, d})) {
        std::array<int, 4> p;
        if (u >= d) {
            p[0] = i - u;
            p[2] = u + d;
            u--;
        } else {
            p[0] = i + d;
            p[2] = -(u + d);
            d--;
        }
        if (l >= r) {
            p[1] = j - l;
            p[3] = l + r;
            l--;
        } else {
            p[1] = j + r;
            p[3] = -(l + r);
            r--;
        }
        ans.push_back(p);
    }

    std::cout << "Yes\n";
    std::cout << ans.size() << "\n";
    for (auto [x, y, h, w] : ans) {
        std::cout << x << " " << y << " " << h << " " << w << "\n";
    }
}

E. Math Problem

题目大意

给定n和k,可以用a的代价将n变为\([kn,k(n+1))\),用b的代价将n变为\(\left\lfloor \frac{n}{k} \right\rfloor\),问让n变成m倍数的最小代价是多少

解题思路

显然一定先进行除法,然后再进行乘法,先预处理除法的代价,然后枚举乘法的代价,最大不会超过mk,然后检查枚举途中除m是否有变化,有则说明中间的某个值会恰好

代码实现

#include <bits/stdc++.h>

using i128 = __int128;

std::ostream &operator<<(std::ostream &out, i128 val) {
    if (val == 0) {
        return out << "0";
    }
    if (val < 0) {
        out << '-', val = -val;
    }
    std::string s;
    while (val > 0) {
        s += '0' + val % 10;
        val /= 10;
    }
    std::reverse(s.begin(), s.end());
    return out << s;
}

std::istream &operator>>(std::istream &in, i128 &val) {
    std::string s;
    in >> s;
    val = 0;
    bool neg = (s[0] == '-');
    for (int i = neg; i < s.size(); i++) {
        val = val * 10 + (s[i] - '0');
    }
    if (neg) {
        val = -val;
    }
    return in;
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int tt;
    std::cin >> tt;

    while (tt--) {
        i128 n, k, m, a, b, cnt = 0;
        std::cin >> n >> k >> m >> a >> b;

        if (k == 1) {
            if (n % m == 0) {
                std::cout << 0 << "\n";
            } else {
                std::cout << -1 << "\n";
            }
        } else {
            i128 x = n, ans = LONG_LONG_MAX;
            std::vector<std::array<i128, 2>> res;
            while (x) {
                res.push_back({x, cnt * b});
                if (x % m == 0) {
                    ans = std::min(ans, cnt * b);
                }
                x /= k;
                cnt++;
            }
            res.push_back({x, cnt * b});
            ans = std::min(res.back()[1], ans);

            if (n % m == 0) {
                ans = 0;
            }

            std::vector<i128> K = {k};
            for (int i = 2; i < 64; i++) {
                i128 x = K.back() * k;
                if (x > m * k) {
                    break;
                }
                K.push_back(x);
            }

            for (auto [p, q] : res) {
                for (int i = 0; i < K.size(); i++) {
                    if (p * K[i] / m != (p * K[i] + K[i] - 1) / m || p * K[i] % m == 0 || (p * K[i] + K[i] - 1) % m == 0) {
                        ans = std::min(ans, q + (i + 1) * a);
                    }
                }
            }

            std::cout << ans << "\n";
        }
    }
}
posted @ 2025-05-09 14:45  udiandianis  阅读(53)  评论(0)    收藏  举报