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.
Only the factors and matter. Try classifying each number into one of four buckets: divisible by , divisible only by , divisible only by , or divisible by neither. The actual value is basically cosmetic here.
Ignore the numbers divisible by for a moment. Then a subarray is good iff it contains at least one “only-” number and at least one “only-” number. Numbers coprime to are just filler.
Suppose there are numbers of type “only ” and numbers of type “only ”. In any arrangement, for every pair consisting of one such -type position and one such -type position, the interval between them is a good subarray. That already gives a lower bound of .
Can you achieve exactly ? Yes: put all “only ” numbers in one block, all “only ” numbers in another block, and put all neutral numbers (not divisible by or ) in the middle. Then the only good subarrays are those that start in the left block and end in the right block.
Now bring back the numbers divisible by . Any subarray containing one of them is automatically good, so these guys are radioactive — shove them to an edge. An optimal construction is or the reverse. That hits the lower bound, so it’s optimal. Clean, brutal, done.
A subarray product is divisible by iff its product has both a factor and a factor .
So every number belongs to exactly one of these four types:
From now on, the actual values are irrelevant. Only the type matters. Competitive programming in a nutshell: kill the fluff, keep the invariant.
Suppose the array contains only , , and .
Then a subarray is good iff it contains:
The 's are just innocent bystanders.
Let there be elements of type and elements of type .
Take any position of a and any position of a . The interval between those two positions is a good subarray.
Different pairs of positions give different intervals, so every arrangement has at least
good subarrays.
Yes. Arrange them as
(or symmetrically ).
Now every good subarray must start in the block and end in the block. So the number of good subarrays is exactly
That matches the lower bound, so this is optimal.
So, without any multiples of , the optimal arrangement is:
Any subarray containing an element of type is automatically good. Those elements are basically landmines.
So to minimize , we want to maximize the number of subarrays that avoid all 's.
If we delete all 's, the remaining elements split into some segments. Let these segments have lengths
Then the number of subarrays avoiding all 's is
This is maximized when there is only one such segment, because
So the non- elements should form one contiguous block. Equivalently, all 's should be pushed to an edge (or split between the two edges — same idea, but one edge is simpler).
Let:
If all non- elements form one block, then:
So an optimal arrangement is simply
or the reverse
That’s it. No DP, no black magic, no goat sacrifice.
Let the -free segments be . For segment , let:
Then:
Subarrays containing at least one contribute
Inside segment , by the same pair argument as before, there are at least good subarrays.
Therefore
Now compare this with the one-block arrangement. Since
and also
while clearly
we get
And the construction achieves exactly this bound. So it is optimal.
For each test case:
That’s all.
Each number is classified once, so the complexity is
per test case, and
over the whole input.
Memory usage is also .
Pretty damn cheap for an optimal construction.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> A, B, C, D;
A.reserve(n);
B.reserve(n);
C.reserve(n);
D.reserve(n);
for (int i = 0; i < n; ++i) {
int x;
cin >> x;
if (x % 6 == 0) A.push_back(x);
else if (x % 2 == 0) B.push_back(x);
else if (x % 3 == 0) C.push_back(x);
else D.push_back(x);
}
bool first = true;
auto output_vec = [&](const vector<int>& v) {
for (int x : v) {
if (!first) cout << ' ';
first = false;
cout << x;
}
};
// Optimal order: [divisible by 6] [only 2] [neither] [only 3]
output_vec(A);
output_vec(B);
output_vec(D);
output_vec(C);
cout << '\n';
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> A, B, C, D;
A.reserve(n);
B.reserve(n);
C.reserve(n);
D.reserve(n);
for (int i = 0; i < n; ++i) {
int x;
cin >> x;
if (x % 6 == 0) A.push_back(x);
else if (x % 2 == 0) B.push_back(x);
else if (x % 3 == 0) C.push_back(x);
else D.push_back(x);
}
bool first = true;
auto output_vec = [&](const vector<int>& v) {
for (int x : v) {
if (!first) cout << ' ';
first = false;
cout << x;
}
};
// Optimal order: [divisible by 6] [only 2] [neither] [only 3]
output_vec(A);
output_vec(B);
output_vec(D);
output_vec(C);
cout << '\n';
}
}