QOJ.ac

QOJ

Type: Editorial

Status: Open

Posted by: jiangly

Posted at: 2025-12-13 00:32:35

Last updated: 2025-12-13 00:32:46

Back to Problem

题解

用归纳法易证,每次将一个前缀分给一个人,如果需要的长度是最短的,则对于剩下的人一定有解。用每个人初始的分割点来划分可以避免分母过大。

时间复杂度:$O(N(N+L))$。

代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <functional>
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int n, l;
    std::cin >> n >> l;
    std::vector<std::vector<int>> v(n, std::vector<int>(l));
    std::vector<std::vector<int>> s(n, std::vector<int>(l + 1));
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < l; ++j) std::cin >> v[i][j];
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < l; ++j) s[i][j + 1] = s[i][j] + v[i][j];
    std::vector<std::vector<std::pair<long long, int>>> r(n, std::vector<std::pair<long long, int>>(n));
    for (int i = 0; i < n; ++i) {
        for (int j = 0, k = 0; j < n; ++j) {
            while (1ll * s[i][k + 1] * n <= 1ll * s[i][l] * j) ++k;
            int den = n * v[i][k];
            r[i][j] = std::make_pair(1ll * s[i][l] * j - 1ll * s[i][k] * n + 1ll * k * den, den);
        }
    }
    std::vector<bool> vis(n);
    std::vector<int> p(n);
    for (int i = 0; i < n - 1; ++i) {
        int u = -1;
        long long num = l * n;
        int den = n;
        for (int j = 0; j < n; ++j) {
            if (vis[j])
                continue;
            auto [x, y] = r[j][i + 1];
            if (x * (den / n) < num * (y / n)) {
                u = j;
                num = x;
                den = y;
            }
        }
        vis[u] = true;
        p[i] = u;
    }
    for (int i = 0; i < n; ++i)
        if (!vis[i])
            p[n - 1] = i;
    for (int i = 1; i < n; ++i) std::cout << r[p[i - 1]][i].first << " " << r[p[i - 1]][i].second << "\n";
    for (int i = 0; i < n; ++i) std::cout << p[i] + 1 << " \n"[i == n - 1];
    return 0;
}

Comments

No comments yet.