Solution Set 2023.12.12

发布时间 2023-12-12 20:25:36作者: User-Unauthorized

ABC332G Not Too Many Balls

可以转化为最大流模型,设节点 \(x_i\) 代表第 \(i\) 种球,\(y_j\) 代表第 \(j\) 个盒子。考虑如下建边方案:

  • \(S \rightarrow x_i\),容量为 \(A_i\)
  • \(x_i \rightarrow y_j\),容量为 \(i \times k\)
  • \(y_j \rightarrow T\),容量为 \(B_j\)

可以发现该网络的最大流即为答案,但是由于边数是 \(\mathcal{O}(NM)\) 级别的,直接求最大流会超时。根据最大流最小割定理,若我们可以求出该网络的最小割,那么我们也可以获得答案,下面考虑如何求出最小割。

首先考虑如何表示出最小割的值,设点集 \(X = \left\{x_1, x_2, \cdots, x_N\right\}, Y = \left\{x_1, x_2, \cdots, x_N\right\}\)\(P\) 表示最小割方案中 \(X\) 中与 \(S\) 在同一连通块内的点集,\(Q\) 表示最小割方案中 \(Y\) 中与 \(S\) 在同一连通块内的点集。那么考虑三条边中都有哪些边被割掉,可以得出最小割的表达式:

\[\begin{aligned} \mathbf{mincut} &= \min\limits_{P \subseteq X} \min\limits_{Q \subseteq Y} \left(\sum\limits_{x_i \in X \setminus P} A_i + \sum\limits_{x_i \in P}\sum\limits_{y_j \in Y \setminus Q} i \times j + \sum\limits_{y_j \in Q} B_j\right) \end{aligned}\]

\(k = \sum\limits_{x_i \in P} i, L = \dfrac{N\left(N + 1\right)}{2}\),通过枚举 \(x\) 的值,我们有:

\[\begin{aligned} \mathbf{mincut} &= \min\limits_{0 \le k \le L} \min\limits_{P \subseteq X \land \sum\limits_{x_i \in P} i = k}\min\limits_{Q \subseteq Y} \left(\sum\limits_{x_i \in X \setminus P} A_i + \sum\limits_{x_i \in P}\sum\limits_{y_j \in Y \setminus Q} i \times j + \sum\limits_{y_j \in Q} B_j\right)\\ &= \min\limits_{0 \le k \le L} \min\limits_{P \subseteq X \land \sum\limits_{x_i \in P} i = k}\min\limits_{Q \subseteq Y} \left(\sum\limits_{x_i \in X \setminus P} A_i + \sum\limits_{y_j \in Y \setminus Q} k \times j + \sum\limits_{y_j \in Q} B_j\right) \\ &= \min\limits_{0 \le k \le L} \min\limits_{P \subseteq X \land \sum\limits_{x_i \in P} i = k}\left(\sum\limits_{x_i \in X \setminus P} A_i + \sum\limits_{y_j \in Y} \min\left\{k \times j, B_j\right\}\right) \end{aligned}\]

其中最后一步转化是因为 \(Y\) 中的每个节点要么属于 \(Q\),要么属于 \(Y \setminus Q\),也就是其会产生 \(k \times j\)\(B_j\) 的贡献,故可以直接取最小值。

对于上式的前半部分,即 \(f_k = \min\limits_{P \subseteq X \land \sum\limits_{x_i \in P} i = k}\sum\limits_{x_i \in X \setminus P} A_i\)。我们可以使用 \(\tt{01}\) 背包在 \(\mathcal{O}(NL)\) 的时间内求出对于 \(0 \le k \le L\) 的所有 \(f_k\) 的值。

对于上式的后半部分,即 \(g_k = \sum\limits_{y_j \in Y} \min\left\{k \times j, B_j\right\}\)。可以发现当 \(k = 0\) 时,所有的节点均会从 \(k \times j\) 来产生贡献,而由于 \(k \times j\)\(k\) 的增长而单调递增,因此对于所有满足 \(y_j \in Y\)\(j\),均存在一个 \(k_0\) 使得当 \(k \ge k_0\) 时,其会产生 \(B_j\) 而不是 \(k \times j\) 的贡献,所以有 \(\forall k \ge k_0, B_j \le k \times j\),解得 \(k_0 = \dfrac{B_j}{j}\)。因此我们对于每个 \(j\) 求出出其对应的 \(k_0\) 后遍历 \(0 \le k \le L\) 并求出 \(g_k\) 即可。

最终答案即为 \(\min\limits_{0 \le k \le L} f_k + g_{L - k}\)。复杂度为 \(\mathcal{O}(N^3 + M)\)

Code
#include <bits/stdc++.h>

typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;

constexpr valueType INF = std::numeric_limits<valueType>::max() >> 3;

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

    valueType N, M;

    std::cin >> N >> M;

    valueType const S = N * (N + 1) / 2;

    ValueVector A(N + 1), B(M + 1);

    for (valueType i = 1; i <= N; ++i)
        std::cin >> A[i];

    for (valueType i = 1; i <= M; ++i)
        std::cin >> B[i];

    ValueVector F(S + 1, INF);

    F[0] = 0;

    for (valueType i = 1; i <= N; ++i) {
        for (valueType j = S; j >= i; --j)
            F[j] = std::min(F[j], F[j - i] + A[i]);
    }

    ValueVector G(S + 1, 0);

    ValueMatrix H(S + 1);

    for (valueType i = 1; i <= M; ++i) {
        valueType const pos = B[i] / i;

        if (pos <= S)
            H[pos].emplace_back(i);
    }

    {
        valueType indexSum = M * (M + 1) / 2, valueSum = 0;

        for (valueType i = 0; i <= S; ++i) {
            G[i] += i * indexSum + valueSum;

            for (auto const &iter : H[i]) {
                indexSum -= iter;

                valueSum += B[iter];
            }
        }
    }

    valueType ans = INF;

    for (valueType i = 0; i <= S; ++i)
        ans = std::min(ans, F[i] + G[S - i]);

    std::cout << ans << std::endl;

    return 0;
}

ARC125E Snack

ABC332G Not Too Many Balls,我们可以将其转化为最大流模型后求其最小割,化简后的最小割表达式为:

\[\min\limits_{P \subseteq X} \min\limits_{Q \subseteq Y} \left(\sum\limits_{x_i \in X \setminus P} A_i + \sum\limits_{y_j \in Y} \min\left\{\left\lvert P \right\rvert \times B_j, C_j\right\}\right) \]

\(f_k = \min\limits_{P \subseteq X \land \left\lvert P \right\rvert = k} \sum\limits_{x_i \in X \setminus P} A_i\) 是平凡的,将 \(A\) 序列排序后做前缀和即可。

对于 \(g_k = \sum\limits_{y_j \in Y} \min\left\{k \times B_j, C_j\right\}\)ABC332G Not Too Many Balls,可以得出 \(k_0 = \dfrac{C_j}{B_j}\)

复杂度为 \(\mathcal{O}(N \log N + M)\)

Code
#include <bits/stdc++.h>

typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;

constexpr valueType INF = std::numeric_limits<valueType>::max() >> 3;

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

    valueType N, M;

    std::cin >> N >> M;

    ValueVector A(N + 1, 0), B(M + 1, 0), C(M + 1, 0);

    for (valueType i = 1; i <= N; ++i)
        std::cin >> A[i];

    for (valueType i = 1; i <= M; ++i)
        std::cin >> B[i];

    for (valueType i = 1; i <= M; ++i)
        std::cin >> C[i];

    ValueVector F = A;

    std::sort(F.begin(), F.end());
    std::partial_sum(F.begin(), F.end(), F.begin());

    ValueVector G(N + 1, 0);
    ValueMatrix bucket(N + 1);

    for (valueType i = 1; i <= M; ++i) {
        valueType const pos = C[i] / B[i];

        if (pos <= N)
            bucket[pos].push_back(i);
    }

    valueType SumB = std::accumulate(B.begin(), B.end(), (valueType) 0), SumC = 0;

    for (valueType i = 0; i <= N; ++i) {
        G[i] = i * SumB + SumC;

        for (auto const &iter : bucket[i]) {
            SumB -= B[iter];
            SumC += C[iter];
        }
    }

    valueType ans = INF;

    for (valueType i = 0; i <= N; ++i)
        ans = std::min(ans, F[i] + G[N - i]);

    std::cout << ans << std::endl;

    return 0;
}