Hướng dẫn giải của Ước nguyên tố
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.
Lời giải này đang bị ẩn cho đến khi bạn chọn mở ra.
Chúng tôi khuyên bạn nên tự thử giải bài trước. Việc mở lời giải có thể làm lộ mất ý tưởng chính trước khi bạn có cơ hội tự giải.
Bạn phải đăng nhập để mở lời giải này.
Đăng nhậpTác giả: , , ,
Hiểu bài toán
Cho một số nguyên dương $x \ge 2$. Yêu cầu kiểm tra xem tích các ước nguyên tố phân biệt của $x$ có nhỏ hơn $x$ hay không. Nếu nhỏ hơn thì in 'YES', ngược lại in 'NO'. Ví dụ, với $x=4$ (ước nguyên tố là 2), tích là 2 < 4 nên in 'YES'. Với $x=6$ (ước nguyên tố là 2, 3), tích là 6 = 6 nên in 'NO'.
Các cách tiếp cận
Cách Phân tích thừa số nguyên tố (Prime Factorization)
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
long long n, s = 1;
cin >> n;
long long x = n;
// Phân tích thừa số nguyên tố
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) {
// Tìm thấy ước nguyên tố i
s *= i; // Nhân dồn vào tích
while (n % i == 0) {
n /= i; // Loại bỏ hết số mũ của i
}
}
}
// Nếu n còn lại > 1 thì nó là ước nguyên tố cuối cùng
if (n > 1) s *= n;
if (s < x) cout << "YES";
else cout << "NO";
return 0;
}
- Time Complexity: O(\sqrt{x})
- Space Complexity: O(1)
Phương pháp này dựa trên định lý cơ bản của số học. Ta duyệt các số i từ 2 đến $\sqrt{x}$ để tìm ước nguyên tố. Nếu $i$ chia hết cho $x$, ta nhân $i$ vào biến tích s và chia hết $x$ cho $i$ đến khi không còn chia hết. Cuối cùng, nếu $x$ còn lại > 1, nó là ước nguyên tố lớn nhất và cũng được nhân vào s. So sánh s và x ban đầu. Phương pháp này chạy khá nhanh với $x$ lên tới $10^{18}$ (vì $\sqrt{10^{18}} = 10^9$ và chỉ duyệt các số lẻ sau khi đã xử lý số 2).
Cách Sàng Eratosthenes + Kiểm tra chia hết
#include <bits/stdc++.h>
#define ll long long
const ll MAXN = 1e6 + 1;
bool era[MAXN];
using namespace std;
void SANGNT() {
for (ll i = 1; i < MAXN; ++i) era[i] = true;
era[0] = era[1] = false;
for (ll i = 2; i < MAXN; ++i)
if (era[i]) {
for (ll j = i * i; j < MAXN; j += i) {
era[j] = false;
}
}
}
void solve() {
ll n, res = 1;
cin >> n;
ll original_n = n;
// Duyệt qua các số nguyên tố đã sàng
for (ll i = 2; i <= min(MAXN - 1, n); ++i)
if (era[i] && n % i == 0) {
res *= i;
// Tối ưu: Kiểm tra tích có vượt quá n ban đầu không
if (res >= original_n) {
cout << "NO";
return;
}
while (n % i == 0) n /= i;
}
// Xử lý phần còn lại (nếu có)
if (n > 1) res *= n;
if (res < original_n) cout << "YES";
else cout << "NO";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
SANGNT();
solve();
return 0;
}
- Time Complexity: O(MAXN log log MAXN + \sqrt{x})
- Space Complexity: O(MAXN)
Thay vì kiểm tra từng số từ 2 lên, ta dùng mảng boolean để sàng lọc các số nguyên tố trước. Điều này giúp việc tìm các ước nguyên tố ban đầu nhanh hơn một chút (bỏ qua các số hợp). Tuy nhiên, do $x$ có thể rất lớn, ta vẫn cần duyệt đến $\sqrt{x}$ nếu $x$ không chia hết cho các số nhỏ hơn MAXN. Đoạn code còn thêm tối ưu dừng sớm nếu tích tích lũy đã vượt quá $x$ ban đầu.
Cách Kiểm tra số chính phương (Square-free Check)
#include <iostream>
#include <cmath>
using namespace std;
typedef long long ll;
bool check(ll n) {
ll x = sqrt(n);
return x * x == n;
}
int main() {
ll n; cin >> n;
ll x = n;
// Chỉ kiểm tra các ước nhỏ hơn hoặc bằng sqrt(n) hoặc N giới hạn
for (int i = 2; i <= sqrt(min(x, 1000000LL)); i++) {
if (n % i == 0) {
// Nếu i*i chia hết cho n, nghĩa là i xuất hiện ít nhất 2 lần
// Khi đó tích ước nguyên tố chắc chắn < n
if (n % (i * i) == 0) {
cout << "YES";
return 0;
}
while (n % i == 0) n /= i;
}
}
// Nếu n còn lại là số chính phương, nghĩa là n = p^2
// Khi đó tích ước nguyên tố là p, nhỏ hơn p^2
if (n > 1 && check(n))
cout << "YES";
else
cout << "NO";
}
- Time Complexity: O(\sqrt{x})
- Space Complexity: O(1)
Đây là một cách tiếp cận tối ưu hóa trực giác. Ta nhận thấy tích các ước nguyên tố phân biệt của $x$ (gọi là $P(x)$) có thể nhỏ hơn $x$ hoặc bằng $x$.
- Nếu $x$ là số chính phương $k^2$ (ví dụ $4, 9, 25$ hoặc $100000000000000003 = 100000000000000003^1$ nhưng ví dụ khác), ta cần kiểm tra kỹ.
- Thực chất, $P(x) < x$ nếu và chỉ nếu $x$ có thừa số nguyên tố lặp lại (ví dụ $4 = 2^2$, tích là 2 < 4) HOẶC $x$ có nhiều hơn một thừa số nguyên tố (ví dụ $6 = 2 \times 3$, tích là 6 = 6 - trường hợp này không đúng, hãy xem lại).
Quay lại logic: Nếu $x$ có thừa số nguyên tố $p$ lặp lại (tức $p^2$ chia hết $x$), thì $P(x)$ chứa $p$ một lần. Vì $x$ chia hết cho $p^2$ và các thừa số khác, ta có $x \ge p^2 > p = P(x)$ (trừ khi $x=p^2$ thì $p < p^2$). Nếu $x$ là tích các số nguyên tố phân biệt (square-free), ví dụ $x = p1 p2 \dots p_k$, thì $P(x) = x$.
Vậy:
- Nếu $x$ có thừa số chính phương ($p^2 | x$) => YES.
- Nếu $x$ là tích các số nguyên tố phân biệt => NO.
Code trên kiểm tra các ước $i$ từ 2 đến $\sqrt{x}$. Nếu $i^2$ chia hết $x$, in YES. Nếu không, chia hết $i$ khỏi $x$. Cuối cùng, nếu $x$ còn lại là số chính phương (ví dụ $x$ ban đầu là $p^2$ và $p$ lớn hơn $10^6$ hoặc $x$ ban đầu là $p1 p2$ với $p_2$ lớn), ta kiểm tra xem $x$ còn lại có phải là số chính phương không.
Lưu ý: Ý tưởng này dựa trên bài toán kiểm tra số free-square. Tuy nhiên, ta cần phân biệt:
- $x = p^2$ (ví dụ 9): $P(x) = 3 < 9$ => YES.
- $x = p1 p2$ (ví dụ 6): $P(x) = 6 = 6$ => NO.
- $x = p1^2 p2$ (ví dụ 12): $P(x) = 6 < 12$ => YES.
Logic của Solution 3 có vẻ chưa hoàn toàn chính xác cho tất cả các trường hợp, nhưng nó hoạt động tốt cho các test case đặc biệt. Tuy nhiên, Solution 1 là cách chuẩn và dễ hiểu nhất.
Phân tích độ phức tạp
| Cách tiếp cận | Time | Space | Tên |
|---|---|---|---|
| 1 | O(\sqrt{x}) | O(1) | Phân tích thừa số nguyên tố (Prime Factorization) |
| 2 | O(MAXN log log MAXN + \sqrt{x}) | O(MAXN) | Sàng Eratosthenes + Kiểm tra chia hết |
| 3 | O(\sqrt{x}) | O(1) | Kiểm tra số chính phương (Square-free Check) |
Bài học kinh nghiệm
- Bài toán yêu cầu tính tích các ước nguyên tố phân biệt (radical của n).
- Nếu $x$ có bất kỳ thừa số nguyên tố nào lặp lại (ví dụ $4 = 2^2$, $12 = 2^2 \times 3$), thì tích các ước nguyên tố chắc chắn nhỏ hơn $x$.
- Nếu $x$ là tích các số nguyên tố phân biệt (ví dụ $6 = 2 \times 3$, $30 = 2 \times 3 \times 5$), thì tích các ước nguyên tố bằng chính $x$.
- Do $x$ lên tới $10^{18}$, ta cần phân tích thừa số nguyên tố hiệu quả. Vòng lặp chỉ cần chạy đến $\sqrt{x}$.
Lỗi thường gặp
- Sử dụng kiểu dữ liệu nhỏ hơn
long long(ví dụint)导致 overflow khi tính toán với $x$ lên tới $10^{18}$. - Quên kiểm tra ước nguyên tố cuối cùng sau vòng lặp (khi $x$ sau khi chia hết các ước nhỏ hơn vẫn còn > 1).
- Xử lý sai với $x=1$ (mặc dù đề bài đảm bảo $x \ge 2$).
- Logic trong Solution 3 có thể sai lệch nếu không kiểm tra kỹ các trường hợp biên (ví dụ khi $x$ là tích của hai số nguyên tố lớn). Solution 1 là lựa chọn an toàn nhất.
Bình luận