Solution Set【2024.1.27】

CF1778F Maximizing Root

首先不难证明不操作根节点一定不优,因此我们考虑操作根节点的情况。

现在我们的问题转化为了:最大化操作根节点前的整个树的节点权值的最大公约数。

由于可能的最大公约数值只有 \(\mathcal{O}(\sqrt{V})\) 种。因此我们考虑将其压入状态进行动态规划。

\(f_{u, j}\) 表示使得 \(u\) 子树内的所有节点点权和根节点点权最大公约数为 \(j\) 的最小操作次数。转移时枚举子树的最大公约数即可,复杂度为 \(\mathcal{O}(n \sqrt{V}^2) = \mathcal{O}(nV)\),可以通过。

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

typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::unordered_map<valueType, valueType> ValueMap;

constexpr valueType MAX = std::numeric_limits<valueType>::max() >> 20;

valueType N, K;
ValueVector Factor, A;
ValueMap Map;
ValueMatrix G, F;

void calc(valueType x, valueType from) {
    for (auto const &to : G[x]) {
        if (to == from)
            continue;

        calc(to, x);

        for (valueType i = 0; i < Factor.size(); ++i) {
            valueType min = MAX;

            for (valueType j = i; j < Factor.size(); ++j)
                if (Factor[j] % Factor[i] == 0)
                    min = std::min(min, F[to][j]);

            F[x][i] += min;
        }
    }

    for (valueType i = 0; i < Factor.size() && from > 0; ++i) {
        if (A[x] % Factor[i] != 0)
            F[x][i] = MAX;
    }

    for (valueType i = Factor.size() - 1; i >= 0 && from > 0; --i) {
        valueType const power = Map[std::__gcd(A[1], Factor[i] * Factor[i])];

        F[x][power] = std::min(F[x][power], F[x][i] + 1);
    }
}

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

    valueType T;

    std::cin >> T;

    for (valueType testcase = 0; testcase < T; ++testcase) {
        Factor.clear();
        A.clear();
        Map.clear();
        G.clear();
        F.clear();

        std::cin >> N >> K;

        A.resize(N + 1, 0);

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

        for (valueType i = 1; i * i <= A[1]; ++i) {
            if (A[1] % i == 0) {
                Factor.push_back(i);

                Factor.push_back(A[1] / i);
            }
        }

        std::sort(Factor.begin(), Factor.end());
        Factor.erase(std::unique(Factor.begin(), Factor.end()), Factor.end());

        for (valueType i = 0; i < Factor.size(); ++i)
            Map[Factor[i]] = i;

        G.resize(N + 1);
        F.resize(N + 1, ValueVector(Factor.size(), 0));

        for (valueType i = 1; i < N; ++i) {
            valueType u, v;

            std::cin >> u >> v;

            G[u].push_back(v);
            G[v].push_back(u);
        }

        calc(1, 0);

        valueType ans = 1;

        for (valueType i = 0; i < Factor.size(); ++i)
            if (F[1][i] < K)
                ans = std::max(ans, Factor[i]);

        ans *= A[1];

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

    return 0;
}

[GDKOI2023 提高组] 矩阵

对于判定问题我们考虑考察其必要条件并进行随机化判定。

不难发现,对于矩阵 \(A, B, C\),若其满足

\[A \times B = C \]

那么对于任意 \(1 \times n\) 的向量 \(x\),其一定满足

\[x \times A \times B = x \times C \]

这样我们可以在 \(\mathcal{O}(n^2)\) 的时间内进行一次判定,下面估计其正确率。

发现实际上我们需要判定的是 \(A \times B - C\) 后得到的矩阵是否均为 \(0\),记其为 \(D\),那么我们通过向量 \(x\) 实际判定的是 \(x \times D\) 得到的向量是否均为 \(0\)。不妨假设 \(D\) 中存在非 \(0\) 的位置,即其为 \(\left(x, y\right)\),那么在我们先在 \(x\) 中除了 \(\left(1, x\right)\) 以外的其他值,那么可以发现,若那个空位在 \(\left[0, 998244353\right)\) 内随机生成,那么 \(x \times D\) 中的 \(\left(1, y\right)\) 的取值也取遍 \(\left[0, 998244353\right)\),因此该做法的错误率不超过 \(\frac{1}{998244353}\),可以接受。

posted @ 2024-01-27 19:05  User-Unauthorized  阅读(15)  评论(0编辑  收藏  举报