GCDARR2. GCD Arrays (Hard)
fix g as the interior GCD, count interior sequences with Möbius inversion, count valid endpoint pairs with inclusion-exclusion — O(M log M + M log N) per test case
Table of contents
Problem Statement
an array of length is called good if:
- for every
every proper subsegment (any contiguous subarray except the full array itself) must have gcd , but the full array’s gcd must be exactly 1.
given and , count the number of good arrays of length with . print the answer modulo .
Examples
Example 1
5 3 3 3 6 3 12 4 12 200000 100
0 4 42 74 263141891
for , : the 4 valid arrays are , , , .
take :
- ✓ (full array)
- ✓
- ✓
- ✓, ✓, ✓
for , : no valid arrays exist — we’ll see why during the explanation.
Constraints
- sum of over all test cases
Explanation
brute force
try all arrays. for each, check both gcd conditions. that’s — completely hopeless for the given constraints.
we need structure.
what does a valid array look like?
let’s say , so the array is . the proper subsegments are: , , , , . all of these must have gcd .
- having gcd just means .
- having gcd means and share a prime.
- having gcd means and share a prime.
- but — they can’t all share the same prime.
for , : the interior is just (can’t be 1). if , then must share a factor with 2 so , and . but then . if , same problem. so 0 valid arrays ✓.
the structure for general
take any valid array. consider the interior elements . every subarray made only from interior elements is a proper subarray, so its gcd . in particular, — the entire interior shares a common factor.
let . we know .
now for the endpoints:
- the subarray must have gcd . that’s — so shares at least one prime with .
- the subarray must have gcd . that’s — so shares at least one prime with .
- the full array must have gcd , which means — no single prime divides all three.
so the answer is:
where:
- — the gcd of the interior elements , iterated from 2 to
- — number of length- sequences in with gcd exactly
- — number of valid pairs for this fixed interior gcd
computing dp[g] — the “exactly g” trick
= number of sequences of length using elements from whose gcd is exactly .
first, let’s count sequences whose gcd is at least (i.e., every element is a multiple of ). there are multiples of in , so:
but this overcounts — it includes sequences with gcd , , etc. we subtract those out:
where:
- — sequences of length in with gcd exactly
- — count of multiples of in (interior elements must all be multiples of )
- — the interior length (total array minus both endpoints)
- — runs over so covers all proper multiples of up to
- — already computed (since ), sequences with gcd exactly
compute from down to so every is already ready. total work: by the harmonic series ().
small example — dp with , (interior has elements)
for : the 9 pairs of interior elements using only multiples of 2 are , minus the pair with gcd 4 (just ) and gcd 6 (just ) = 7. ✓
computing pairs(g) — the Möbius trick
we need: how many pairs satisfy:
step 1 — how many integers in share a prime with ?
let’s count the complement first: integers coprime to .
if and , we want integers from 1 to 20 not divisible by 2, 3, or 5. by inclusion-exclusion:
the Möbius function packages these alternating signs automatically:
for divisors of :
| factorization | ||
|---|---|---|
| 1 | — | 1 |
| 2 | prime | −1 |
| 3 | prime | −1 |
| 5 | prime | −1 |
| 6 | 2·3 | 1 |
| 10 | 2·5 | 1 |
| 15 | 3·5 | 1 |
| 30 | 2·3·5 | −1 |
so the inclusion-exclusion above is exactly:
where:
- — count of integers in coprime to
- — runs over every divisor of
- — Möbius value: for even number of distinct prime factors, for odd, if any squared prime factor (those cancel and are skipped)
- — count of multiples of in
and it counts the integers in coprime to . why does this work? the Möbius function has a key identity: for any ,
this cancellation is exactly what makes the inclusion-exclusion over prime subsets exact — overcounted elements cancel out.
so: integers share at least one prime with . both endpoints need this, giving candidate pairs.
step 2 — subtract pairs where
a pair is invalid if some prime divides both and . count these using the same inclusion-exclusion idea, but now for pairs:
where:
- — count of valid endpoint pairs for interior gcd
- — both endpoints chosen from integers sharing a prime with
- — runs over non-trivial divisors of (skipping )
- — pairs where both and are divisible by
- — inclusion-exclusion sign, same as before but now applied to pairs
vs : if counts elements divisible by , then counts pairs where both are — that’s the set being inclusion-excluded.
traced example — ,
| 1 | 1 | 6 | 36 |
| 2 | −1 | 3 | 9 |
| 3 | −1 | 2 | 4 |
| 6 | 1 | 1 | 1 |
base: candidate pairs.
correction (, both endpoints divisible by ):
- : (pairs where both divisible by 2: )
- : (pairs where both divisible by 3: )
- : (pairs where both divisible by 6: , added back)
correction total: .
the 4 valid pairs are — is divisible by 2 only, by 3 only (or vice versa), so no shared prime with on both endpoints simultaneously.
putting it all together
for , : the only giving non-zero pairs is (pairs = 4, dp[6] = 1). all other have pairs = 0 because the prime structure of small forces both endpoints to share the same factor, violating the gcd = 1 condition.
answer = ✓.
complexity
| step | cost |
|---|---|
| precomputation (linear sieve) | |
| divisor lists | |
| dp (harmonic series sum) | per test case |
| pairs (divisor iteration) | per test case |
| fast exponentiation in dp | per test case |
| total | per test case |
since sum of , total across all test cases is fine.
Code
solve() — dp + pairs
void solve() {
long long N, M; cin >> N >> M;
vector<long long> dp(M + 1, 0);
for (long long g = M; g >= 1; g--) {
dp[g] = pw(M / g, N - 2);
for (long long k = 2 * g; k <= M; k += g)
dp[g] = (dp[g] - dp[k] + MOD) % MOD;
}
long long ans = 0;
for (long long g = 2; g <= M; g++) {
if (!dp[g]) continue;
// S_g = #{x in [1,M] : gcd(x,g) = 1} via Möbius
long long Sg = 0;
for (int d : divs[g]) {
if (!mu[d]) continue;
long long fl = (M / d) % MOD;
if (mu[d] == 1) Sg = (Sg + fl) % MOD;
else Sg = (Sg - fl + MOD) % MOD;
}
long long MSg = (M % MOD - Sg + MOD) % MOD;
long long pairs = MSg * MSg % MOD;
// inclusion-exclusion correction: sum_{d|g, d>1} mu(d)*floor(M/d)^2
for (int d : divs[g]) {
if (d == 1 || !mu[d]) continue;
long long fl = (M / d) % MOD;
long long term = fl * fl % MOD;
if (mu[d] == 1) pairs = (pairs + term) % MOD;
else pairs = (pairs - term + MOD) % MOD;
}
ans = (ans + dp[g] * pairs) % MOD;
}
cout << ans << "\n";
}
Full code
Full solution — GCDARR2
#include <bits/stdc++.h>
using namespace std;
const long long MOD = 998244353;
const int MAXM = 200001;
int mu[MAXM];
vector<int> divs[MAXM];
long long pw(long long a, long long b) {
long long r = 1;
a %= MOD;
for (; b > 0; b >>= 1, a = a * a % MOD)
if (b & 1) r = r * a % MOD;
return r;
}
void precompute() {
vector<int> primes;
vector<bool> comp(MAXM, false);
mu[1] = 1;
for (int i = 2; i < MAXM; i++) {
if (!comp[i]) { primes.push_back(i); mu[i] = -1; }
for (int j = 0; j < (int)primes.size() && (long long)i * primes[j] < MAXM; j++) {
comp[i * primes[j]] = true;
if (i % primes[j] == 0) { mu[i * primes[j]] = 0; break; }
mu[i * primes[j]] = -mu[i];
}
}
for (int i = 1; i < MAXM; i++)
for (int j = i; j < MAXM; j += i)
divs[j].push_back(i);
}
void solve() {
long long N, M; cin >> N >> M;
vector<long long> dp(M + 1, 0);
for (long long g = M; g >= 1; g--) {
dp[g] = pw(M / g, N - 2);
for (long long k = 2 * g; k <= M; k += g)
dp[g] = (dp[g] - dp[k] + MOD) % MOD;
}
long long ans = 0;
for (long long g = 2; g <= M; g++) {
if (!dp[g]) continue;
long long Sg = 0;
for (int d : divs[g]) {
if (!mu[d]) continue;
long long fl = (M / d) % MOD;
if (mu[d] == 1) Sg = (Sg + fl) % MOD;
else Sg = (Sg - fl + MOD) % MOD;
}
long long MSg = (M % MOD - Sg + MOD) % MOD;
long long pairs = MSg * MSg % MOD;
for (int d : divs[g]) {
if (d == 1 || !mu[d]) continue;
long long fl = (M / d) % MOD;
long long term = fl * fl % MOD;
if (mu[d] == 1) pairs = (pairs + term) % MOD;
else pairs = (pairs - term + MOD) % MOD;
}
ans = (ans + dp[g] * pairs) % MOD;
}
cout << ans << "\n";
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
precompute();
int T; cin >> T;
while (T--) solve();
}
Complexity
- Preprocessing: — linear sieve + divisor lists
- Per test case: — dp sweep + pairs computation
- Total: summed over test cases (sum of )
Resources
- GCDARR2 — problem
- editorial
- GCDARR — easier version — same dp[g] formula, start here
- ABC162E — Sum of gcd of Tuples (Hard) — same exact-GCD DP, full array version
- CF 1750D — Count GCD — inclusion-exclusion over divisors
- COPRIME3 — Coprime Triples — Möbius for exact GCD, simpler warmup
- cp-algorithms — Inclusion-Exclusion
- Möbius Inversion for CP — harmonic series + floor-block trick