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}\),可以接受。