Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
Forget gcd directly. Two numbers have gcd exactly when they share some prime factor.
For any two chosen indices , you can always make both values even with cost at most . So the answer is never worse than the sum of the two smallest values.
That upper bound kills a lot of nonsense: an optimal improving solution never needs to increment both chosen elements more than once. Making both even would already be no worse.
If some element gets increments, then the other chosen element should get increments. Also, the element getting increments must be an index with minimum ; otherwise pairing it with the cheapest index and making both even dominates it.
So check three cases: two original numbers already share a prime, one number after shares a prime with another original number, and the cheapest- element is incremented until divisible by a prime factor of some other original number.
The key fact is simple:
Two numbers have gcd greater than iff they share at least one prime factor.
So every successful plan is secretly choosing a prime and making two values divisible by .
The cheap upper bound
Pick the two indices with the smallest operation costs. Call their costs and after sorting conceptually by cost.
We can always make both chosen values even. Each one needs either or increment, so the total cost is at most
This is our baseline answer. It is also the hammer that smashes the search space.
Why big moves are rare
Suppose we are looking at some chosen pair.
If both elements are incremented at least twice, then the cost is already at least
while making those same two elements even costs at most
So that is never optimal. Easy deletion.
If one element is incremented at least twice and the other is incremented once, the same kind of domination happens:
and again making the pair even is no worse.
Therefore, if an optimal solution has a “big move” of increments, the other element must be left unchanged.
Now ask: which element is allowed to receive this big move?
Let be an index with minimum cost . Suppose some other index gets increments. That costs
But we could instead make indices and both even, costing at most
So a non-cheapest element doing multiple increments is also dominated. Brutal, but fair.
Conclusion:
That gives us the full case split.
Case 1: zero increments
We need two original values sharing a prime factor.
Precompute the distinct prime factors of every number up to . Then scan all and count which prime factors have appeared. If a prime factor appears in two different elements, answer is .
Case 2: exactly one increment total
Try incrementing each index once. We need to share a prime factor with some other original value.
Use the same prime-factor counts. Temporarily remove the factors of from the counts so we do not accidentally match the element with itself. Then check the factors of . If any of them still appears, we can achieve the goal with cost .
So update:
What about one increment on both elements?
That costs at least the sum of two operation costs, so it is never better than the baseline . We already have that covered. No need to chase that rabbit hole.
Case 3: multiple increments on one element
Only the cheapest-cost index can matter. Let it be .
The other chosen element must stay unchanged, so the common prime must be one of the prime factors of some original value where .
For every such prime , compute how many increments are needed to make divisible by :
The cost is
Take the minimum over all prime factors of all other original elements.
That is it. The problem looks like “maybe arbitrary increments,” but the cost ordering forces almost everything into or increments. The only wild card is the cheapest index, and even that only has to aim at primes already present somewhere else.
Complexity
Let . Precomputing distinct prime factors takes
Each test case processes the prime factors of and , so the total work is
where is the number of distinct prime factors. Under these constraints, that is very comfortably fast.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
const int MAXV = 200000 + 5;
vector<vector<int>> pfac(MAXV);
vector<int> cnt(MAXV, 0);
void build_factors() {
for (int p = 2; p < MAXV; p++) {
if (!pfac[p].empty()) continue;
for (int x = p; x < MAXV; x += p) {
pfac[x].push_back(p);
}
}
}
int main() {
setIO();
build_factors();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<int> a(n);
vector<ll> b(n);
for (int &x : a) cin >> x;
for (ll &x : b) cin >> x;
int first = -1, second = -1;
for (int i = 0; i < n; i++) {
if (first == -1 || b[i] < b[first]) {
second = first;
first = i;
} else if (second == -1 || b[i] < b[second]) {
second = i;
}
}
ll ans = b[first] + b[second];
vector<int> touched;
auto add_count = [&](int p) {
if (cnt[p] == 0) touched.push_back(p);
cnt[p]++;
};
for (int i = 0; i < n; i++) {
for (int p : pfac[a[i]]) {
if (cnt[p] > 0) ans = 0;
add_count(p);
}
}
for (int i = 0; i < n; i++) {
for (int p : pfac[a[i]]) cnt[p]--;
for (int p : pfac[a[i] + 1]) {
if (cnt[p] > 0) ans = min(ans, b[i]);
}
for (int p : pfac[a[i]]) cnt[p]++;
}
int cheap = first;
for (int i = 0; i < n; i++) {
if (i == cheap) continue;
for (int p : pfac[a[i]]) {
ll add = (p - a[cheap] % p) % p;
ans = min(ans, add * b[cheap]);
}
}
cout << ans << '\n';
for (int p : touched) cnt[p] = 0;
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
const int MAXV = 200000 + 5;
vector<vector<int>> pfac(MAXV);
vector<int> cnt(MAXV, 0);
void build_factors() {
for (int p = 2; p < MAXV; p++) {
if (!pfac[p].empty()) continue;
for (int x = p; x < MAXV; x += p) {
pfac[x].push_back(p);
}
}
}
int main() {
setIO();
build_factors();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<int> a(n);
vector<ll> b(n);
for (int &x : a) cin >> x;
for (ll &x : b) cin >> x;
int first = -1, second = -1;
for (int i = 0; i < n; i++) {
if (first == -1 || b[i] < b[first]) {
second = first;
first = i;
} else if (second == -1 || b[i] < b[second]) {
second = i;
}
}
ll ans = b[first] + b[second];
vector<int> touched;
auto add_count = [&](int p) {
if (cnt[p] == 0) touched.push_back(p);
cnt[p]++;
};
for (int i = 0; i < n; i++) {
for (int p : pfac[a[i]]) {
if (cnt[p] > 0) ans = 0;
add_count(p);
}
}
for (int i = 0; i < n; i++) {
for (int p : pfac[a[i]]) cnt[p]--;
for (int p : pfac[a[i] + 1]) {
if (cnt[p] > 0) ans = min(ans, b[i]);
}
for (int p : pfac[a[i]]) cnt[p]++;
}
int cheap = first;
for (int i = 0; i < n; i++) {
if (i == cheap) continue;
for (int p : pfac[a[i]]) {
ll add = (p - a[cheap] % p) % p;
ans = min(ans, add * b[cheap]);
}
}
cout << ans << '\n';
for (int p : touched) cnt[p] = 0;
}
}