Post

Codeforces Div 3 Round 900 Problem F

Solution & proof

Introduction

I highly suggest trying out the Problem first before reading the solution.

Concepts: Number Theory, GCD, Prime Factorization, Fundamental Theorem of Arithmetic

Key insight

The key insight here is the fact that:

\[\exists n, a \in \mathbb{Z}^+ \colon gcd(n, a) = 1 \land d(n\cdot a) = n \Longleftrightarrow d(n) \mid n\]

i.e. There exist positive integers n and a, such that gcd(n, a) = 1 and d(n * a) = n, if and only if, d(n) divides n.

Proof

Let’s start by defining a property $P(x, a):$

\[P(x, a) \equiv GCD(x, a) = 1 \land d(x\cdot a) = x\] \[x, a\in \mathbb{Z}^+\]

We are given $n$ such that $n \in \mathbb{Z}^+$

What $a$ should we pick to satisfy $P(n, a)$ or show that no such $a$ exists?

First, let us check how to pick $a$ such that $GCD(n, a) = 1$

The fundamental theorem of arithmetic states that each integer $x > 1$ can be represented uniquely as a product of prime numbers:

\[\begin{equation} \forall n \in \mathbb{Z}^+, x = p_{1}^{e_{1}} \cdot p_{2}^{e_{2}} \cdot p_{3}^{e_{3}} \cdot ... \label{eq:1} \end{equation}\]

or equivalently:

\[n = \prod_{i=1}^\infty p_ie^i\]

Where $p_i$ denotes the $i_{th}$ prime number.

With this in mind, we can say that:

\[x = p_{1}^{e_{1}} \cdot p_{2}^{e_{2}} \cdot p_{3}^{e_{3}} \cdot ...\] \[y = p_{1}^{f_{1}} \cdot p_{2}^{f_{2}} \cdot p_{3}^{f_{3}} \cdot ...\] \[GCD(x, y) = p_{1}^{min(e_{1}, f_{1})} \cdot p_{2}^{min(e_{2}, f_{2})} \cdot p_{3}^{min(e_{3}, f_{3})} \cdot ...\]

Let $P_n$ be the set of all prime factors of $n$. Given the definition of GCD above, we can see that picking an $a$ such that $P_a \cap P_n \neq \varnothing$ will give a $GCD(x,y) > 1$. So we must pick an $a$ such that: \(\forall p \in P_a, p \not\in P_n\) This will guarantee that $GCD(n, a) = 1$

Now, how do we make sure that $d(n\cdot a) = n$ or that $a$ doesn’t exist?

Again, by the fundamental theorem of arithmetic, we can define d(n) like this:

\[n = p_{1}^{e_{1}} \cdot p_{2}^{e_{2}} \cdot p_{3}^{e_{3}} \cdot ... \tag{by $\eqref{eq:1}$}\] \[d(n) = max(1, e_{1}+1) \cdot max(1, e_{2}+1) \cdot max(1, e_{3}+1) \cdot ...\] \[d(n)\in \mathbb{Z}^+\]

Since we must satisfy $GCD(n, a) = 1$, $a$ must not have any prime factor that is in $P_n$:

\[a = q_{1}^{f_{1}} \cdot q_{2}^{f_{2}} \cdot q_{3}^{f_{3}} \cdot ... \tag{by $\eqref{eq:1}$}\] \[d(a) = max(1, f_{1}+1)\cdot max(1, f_{2}+1) \cdot max(1, f_{3}+1) \cdot ...\] \[\begin{equation} d(n\cdot a) = d(n)\cdot d(a) \label{eq:2} \end{equation}\]

Notice that we can always form any integers we want for $d(a)$ (as there are infinitely many prime numbers)

Finally, in order for $d(n \cdot a)$ to equal $n$:

\[n = d(n) \cdot d(a) \tag{by $\eqref{eq:2}$}\] \[d(n) \mid n\tag*{$\blacksquare$}\]

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <iomanip>
#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <algorithm>
#include <numeric>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <cmath>
#include <stack>
#include <queue>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

void get_pfs(int n, map<int, int>& pFactorByCount)
{
    if (n % 2 == 0 && pFactorByCount.find(2) == pFactorByCount.end())
        pFactorByCount[2] = 0;
   
    while (n % 2 == 0)
    {
        pFactorByCount[2]++;
        n = n/2;
    }
 
    for (int i = 3; i <= sqrt(n); i = i + 2)
    {
        if (pFactorByCount.find(i) == pFactorByCount.end())
                pFactorByCount[i] = 0;
        while (n % i == 0)
        {
            pFactorByCount[i]++;
            n = n/i;
        }
    }
   
    if (n > 2){
        if (pFactorByCount.find(n) == pFactorByCount.end())
            pFactorByCount[n] = 0;
        pFactorByCount[n]++;
    }
}


int countDivisors(map<int, int>& pFactorByCount) {
    int ans = 1;
    for (auto& kvp : pFactorByCount)
        ans *= (kvp.second + 1);
    return ans;
}

bool answer(map<int, int>& pFactorByCount){
    int cnt = countDivisors(pFactorByCount);
    for (auto kvp : pFactorByCount){
        if (cnt == 1) break;
        while (kvp.second--){
            if (cnt % kvp.first != 0){
                break;
            }
            cnt /= kvp.first;
            if (cnt == 1) break;
        }
    }
    return cnt == 1;
}

void solve(){
    int N, q;
    cin >> N >> q;
    ull n = N;
    map<int, int> pFactorByCountOrig;
    get_pfs(N, pFactorByCountOrig);
    map<int, int> pFactorByCount = pFactorByCountOrig;
    while (q--){
        int k;
        cin >> k;
        if (k == 1){
            int x;
            cin >> x;
            n *= x;
            get_pfs(x, pFactorByCount);
            if (answer(pFactorByCount)) cout << "YES\n";
            else cout << "NO\n";
        }
        else {
            n = N;
            pFactorByCount = pFactorByCountOrig;
        }
    }
}

int main(){
    ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    //std::cout << std::setprecision(9); // use it for output that requires some precision
    int t=1;
    cin >> t;
    while (t--){
        solve();
    }
}
This post is licensed under CC BY 4.0 by the author.