VP Codeforces Round 889 (Div. 2)
A. Dalton the Teacher
题意:给你一个排列,每次交换两个数,使得\(i \ne p_i\)的最少操作数。
记录\(i = p_i\)的位置个数\(cnt\),答案就是\(\lceil \frac{cnt}{2} \rceil\)。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
-- a[i];
}
int cnt = 0;
for (int i = 0; i < n; ++ i) {
cnt += a[i] == i;
}
std::cout << (cnt + 1) / 2 << "\n";
}
B. Longest Divisors Interval
题意:给你一个整数,求一个区间,使得这个区间的所有数都是\(n\)的因子,且区间长度最大。
假设区间是\([l, r]\),那么这些数的因子一定包含了\([1, r - l + 1]\)。
那么从小到大枚举即可。
点击查看代码
void solve() {
i64 n;
std::cin >> n;
i64 ans = 1;
while (n % (ans + 1) == 0) {
++ ans;
}
std::cout << ans << "\n";
}
C1 && C2. Dual
题意:你要是\(a\)非递减。每次可以选择\(i, j\)使得\(a_i = a_i + a_j\)。求方案,\(C1\)操作数不能超过\(50\),\(C2\)不能超过 \(31\)。
如果只有正数或者负数,那么直接前缀和或者后缀和就能满足。
否则我们可以枚举把这些数变成负数还是正数。然后分别前缀和或后缀和。取答案长度最小的。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<i64> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
int pmax = std::max_element(a.begin(), a.end()) - a.begin();
int pmin = std::min_element(a.begin(), a.end()) - a.begin();
int max = a[pmax], min = a[pmin];
if (min >= 0) {
std::cout << n - 1 << "\n";
for (int i = 1; i < n; ++ i) {
std::cout << i + 1 << " " << i << "\n";
}
return;
}
if (max <= 0) {
std::cout << n - 1 << "\n";
for (int i = n - 2; i >= 0; -- i) {
std::cout << i + 1 << " " << i + 2 << "\n";
}
return;
}
std::vector<std::pair<int, int>> ans1;
std::vector<std::pair<int, int>> ans2;
int t = max;
while (t < -min) {
ans1.emplace_back(pmax, pmax);
t *= 2;
}
for (int i = 0; i < n; ++ i) {
if (a[i] < 0) {
ans1.emplace_back(i, pmax);
}
}
for (int i = 1; i < n; ++ i) {
ans1.emplace_back(i, i - 1);
}
t = min;
while (-t < max) {
ans2.emplace_back(pmin, pmin);
t *= 2;
}
for (int i = 0; i < n; ++ i) {
if (a[i] > 0) {
ans2.emplace_back(i, pmin);
}
}
for (int i = n - 2; i >= 0; -- i) {
ans2.emplace_back(i, i + 1);
}
auto ans = ans1;
if (ans2.size() < ans1.size()) {
ans = ans2;
}
std::cout << ans.size() << "\n";
for (auto & [i, j] : ans) {
std::cout << i + 1 << " " << j + 1 << "\n";
}
}