Hướng dẫn giải của [200 đề thầy Đức] Bài 96: Thừa số nguyên tố thứ K


Chỉ dùng lời giải này khi không có ý tưởng, và đừng copy-paste code từ lời giải này. Hãy tôn trọng người ra đề và người viết lời giải.
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.

Hướng dẫn giải

Bài yêu cầu phân tích $n$ thành thừa số nguyên tố, liệt kê các thừa số (kể cả lặp lại) theo thứ tự tăng dần, rồi in thừa số thứ $k$. Nếu số thừa số ít hơn $k$ thì in $-1$.

Sub 1: Vét cạn — ~O(n)~, dùng khi ~n \le 10^6~

Thử mọi số $d$ từ $2$ đến $n$. Mỗi khi $d$ chia hết số còn lại $m$ thì ghi $d$ vào danh sách và chia $m$ cho $d$, lặp lại cho đến khi không chia hết nữa. Vì thử $d$ theo thứ tự tăng dần nên danh sách đã được sắp xếp sẵn.

Kết quả chấm riêng sub này: đúng 11/21 test (các test còn lại quá giờ vì $n$ lớn hơn miền của sub).

Sub 2: Thử đến căn bậc hai — ~O(\sqrt{n})~, dùng cho ~n \le 10^9~

Nếu $m$ có ước nguyên tố $d$ thì $d$ không vượt quá $\sqrt{m}$, trừ khi $m$ là một số nguyên tố lớn. Vì vậy chỉ cần thử $d$ với $d \cdot d \le m$ và chia hết đến hết. Sau vòng lặp, nếu $m > 1$ thì $m$ chính là một thừa số nguyên tố lớn nhất và được thêm vào cuối danh sách.

Bẫy cần chú ý: khi thử $d \cdot d \le m$ phải dùng kiểu long long để tránh tràn số, và $m$ thay đổi trong lúc chia nên điều kiện dừng dùng $m$ hiện tại.

Kết quả chấm riêng sub này: đúng 21/21 test.

Chương trình hoàn chỉnh

Chương trình đọc $T$, rồi với mỗi test đọc $n, k$. Nếu $n \le 10^6$ thì gọi sub1, ngược lại gọi sub2. Khi đi thi nên viết như vậy: sub1 vẫn ăn điểm các test nhỏ nếu sub2 chưa làm kịp.

#include <bits/stdc++.h>
using namespace std;

long long n;
int k;

// Sub 1: vét cạn — thử mọi ước d từ 2 đến n, chia hết thì lấy hết thừa số d
// Dùng khi n <= 10^6
void sub1() {
    vector<long long> f;
    long long m = n;
    for (long long d = 2; d <= m; d++)
        while (m % d == 0) { f.push_back(d); m /= d; }
    if (k > (int)f.size()) cout << -1 << "\n";
    else cout << f[k - 1] << "\n";
}

// Sub 2: thử chia đến căn bậc hai của n — dùng cho n lớn (đến 10^9)
// Sau khi chia hết hết các ước <= sqrt(m), phần m còn lại (nếu > 1) là một thừa số nguyên tố lớn
void sub2() {
    vector<long long> f;
    long long m = n;
    for (long long d = 2; d * d <= m; d++)
        while (m % d == 0) { f.push_back(d); m /= d; }
    if (m > 1) f.push_back(m);
    if (k > (int)f.size()) cout << -1 << "\n";
    else cout << f[k - 1] << "\n";
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T;
    cin >> T;
    while (T--) {
        cin >> n >> k;
        if (n <= 1000000) sub1();   // n nhỏ: vét cạn cho chắc
        else sub2();                // n lớn: chỉ thử đến căn bậc hai
    }
    return 0;
}

Bình luận

Hãy đọc nội quy trước khi bình luận.


Không có bình luận tại thời điểm này.