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\),若其满足
那么对于任意 \(1 \times n\) 的向量 \(x\),其一定满足
这样我们可以在 \(\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}\),可以接受。

                
            
        
浙公网安备 33010602011771号