Olympic Sinh Viên 2020 - Không chuyên - Phân số
===
[https://oj.vnoi.info/problem/olp_kc20_fraction](https://oj.vnoi.info/problem/olp_kc20_fraction)
Co-author: [Nguyễn Nam](https://www.facebook.com/nguyennam.2018)
-----
### Bài toán con
> Xét bài toán kiểm tra xem phân số $\frac{X}{Y}$ có phải là số thập phân tuần hoàn vô hạn hay không
Xét $\frac{A}{B} = \frac{X \div gcd(X, Y)}{Y \div gcd(X, Y)}$ là phân số tối giản của $\frac{X}{Y}$.
Khi $B = 2^u \times 5^v$ với $u, v \in \mathbb{N}$ thì $\frac{A}{B} = \frac{A \times 2^{k - u} \times 5^{k - v}}{10^k}$ với $k = max(u, v)$. Nên $\frac{A}{B}$ là số thập phân hữu hạn
Ngược lại $\exists$ số nguyên tố $p \notin \{2, 5\}$ thỏa $B\ \vdots\ p$. Ta sẽ chứng minh $\frac{A}{B}$ vô hạn tuần hoàn
Giả sử $\frac{A}{B}$ hữu hạn hay $\frac{A}{B} = \overline{c_1c_2\dots c_u\LARGE,\normalsize d_1d_2 \dots d_v}$
$\Rightarrow \frac{A}{B} \times 10^v = \overline{c_1c_2\dots c_ud_1d_2 \dots d_v}$
$\Rightarrow \Large \frac{A \times 10^v}{B} \normalsize \in \mathbb{Z}$
$\Rightarrow A \times 10^v\ \vdots\ B$
$\Rightarrow\ \ \ 10^v\ \ \ \ \vdots\ B\ \ \ \ \ \ \ \ \ \ \ \ \Large($ vì $\frac{A}{B}$ tối giản $\Rightarrow (A, B) = 1\Large)$
$\Rightarrow\ \ \ 10^v\ \ \ \ \vdots\ \ p\ \ \ \ \ \ \ \ \ \ \ \ \Large($ vì $B\ \vdots\ p \Large)$
Mà $gcd(p, 10) = 1 \Rightarrow \Large(\normalsize dpcm\Large)$
**Kết luận:**
- $\frac{A}{B}$ vô hạn tuần hoàn khi và chỉ khi tồn tại số nguyên tố $p \notin \{2, 5\}$ mà $B\ \vdots\ p$
- $\frac{X}{Y}$ vô hạn tuần hoàn khi và chỉ khi tồn tại số nguyên tố $p \notin \{2, 5\}$ mà $\frac{Y}{gcd(X,Y)}\ \vdots\ p$
-----
### Bài toán chính
> Kiểm tra $\frac{\overset{n}{\underset{i = 1}{\Large \prod}} \Large( \normalsize a_i \Large)}{\overset{n}{\underset{i = 1}{\Large \prod}} \Large( \normalsize b_i \Large)} = \frac{a_1 \times a_2 \times \dots \times a_n}{b_1 \times b_2 \times \dots \times b_n} = \Large \frac{X}{Y}$ có phải là số thập phân vô hạn tuần hoàn hay không
Đặt $p_1, p_2, \dots, p_k$ là các số nguyên tố phân biệt, khi đó ta có:
- $X = p_1 ^ {d_1} \times p_2 ^ {d_2} \times \dots \times p_k ^ {d_k}$ với $d_i \in \mathbb{N}$
- $Y = p_1 ^ {f_1} \times p_2 ^ {f_2} \times \dots \times p_k ^ {f_k}$ với $f_i \in \mathbb{N}$
- $G = gcd(X, Y) = p_1 ^ {min(d_1, f_1)} \times p_2 ^ {min(d_2, f_2)} \times \dots \times p_k ^ {min(d_k, f_k)}$
- $B = gcd(X, Y) = p_1 ^ {f_1 - min(d_1, f_1)} \times p_2 ^ {min(d_2, f_2)} \times \dots \times p_k ^ {min(d_k, f_k)}$
Áp dụng bài toán con, ta có phân số $\frac{X}{Y}$ là số thập phân vô hạn tuần hoàn khi và chỉ khi tồn tại vị trí $x$ để $p_x \notin \{2, 5\}$ mà $f_x - min(d_x, f_x) > 0 \Leftrightarrow f_x - d_x > 0$
Vậy ta chỉ cần phân tích thừa số nguyên tố các số $a_i, b_i$ và kiểm tra từng số nguyên tố $p \notin \{2, 5\}$ xem có thỏa hay không
-----
### Code
> Với $v = max\Large(\normalsize max(a_i, b_i) \Large\ \ \normalsize i = 1\dots n \Large)$
> **Time:** $O(q \times n \times log_2(v))$
> **Space:** $O(q \times (n + v))$
> **Algo:** Sieving, Factorization, Implementation
```cpp=
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int LIM = 1e6 + 1;
/// SPyofgame linear sieving
vector<int> prime; /// prime list
vector<int> lpf; /// lowest prime factor
void sieve(int n = LIM)
{
prime.assign(1, 2);
lpf.assign(n + 1, 2);
lpf[1] = -2;
for (int x = 3; x <= n; x += 2)
{
if (lpf[x] == 2) prime.push_back(lpf[x] = x);
for (int i = 0; i < prime.size() && prime[i] <= lpf[x] && prime[i] * x <= n; ++i)
lpf[prime[i] * x] = prime[i];
}
}
int G[LIM];
int query()
{
int n;
cin >> n;
bool ok = false;
memset(G, 0, sizeof(G));
for (int i = 1; i <= 2 * n; ++i)
{
int x;
cin >> x;
if (ok) continue;
while (x > 1)
{
int p = lpf[x], f = 0;
do x /= p, ++f;
while (lpf[x] == p);
if (p == 2 || p == 5) continue;
if (i <= n)
G[p] -= f;
else
{
G[p] += f;
if (G[p] > 0) /// f[i] - d[i] > 0
{
ok = true;
break;
}
}
}
}
cout << (ok ? "repeating\n" : "finite\n");
return 0;
}
int main()
{
ios::sync_with_stdio(NULL);
cin.tie(NULL);
int q;
cin >> q;
sieve();
while (q-->0)
{
query();
}
return 0;
}
```