Hướng dẫn cho Tìm bộ số


Chỉ sử dụng khi thực sự cần thiết như một cách tôn trọng tác giả và người viết hướng dẫn này.

Chép code từ bài hướng dẫn để nộp bài là hành vi có thể dẫn đến khóa tài khoản.

Authors: PhuocThien

1. Phân tích bài toán

Yêu cầu: Tìm hai số nguyên \(a, b\) sao cho \(a \times b = N\)\(|a - b|\) đạt giá trị nhỏ nhất.
Gọi \(M = |N|\) là giá trị tuyệt đối của \(N\).

Trường hợp \(N = 0\):

  • Ta có thể chọn \(a = 0, b = 0\).
  • Khi đó \(0 \times 0 = 0\)\(|0 - 0| = 0\).
  • Kết quả: 0.

Trường hợp \(N > 0\):

  • Để \(a \times b > 0\), hai số \(a\)\(b\) phải cùng dấu. Để \(|a - b|\) nhỏ nhất, ta xét \(a, b\) cùng dương.
  • Giả sử \(a \le b\). Khi đó \(a \times b = N \Rightarrow a \le \sqrt{N}\).
  • Hiệu \(b - a\) nhỏ nhất khi \(a\)\(b\) gần nhau nhất.
  • Giải pháp: Tìm ước lớn nhất của \(N\) mà không vượt quá \(\sqrt{N}\). Gọi ước đó là \(a\), số còn lại là \(b = N/a\).
  • Kết quả: \(b - a\).

Trường hợp \(N < 0\):

  • Để \(a \times b < 0\), hai số \(a\)\(b\) phải trái dấu.
  • Gọi \(a\)\(b\) là hai ước dương của \(M\) sao cho \(a \times b = M\). Cặp số cần tìm sẽ là \((a, -b)\) hoặc \((-a, b)\).
  • Khi đó \(|a - (-b)| = a + b\).
  • Theo bất đẳng thức Cauchy, \(a + b\) nhỏ nhất khi \(a\)\(b\) gần nhau nhất (tích \(a \times b\) không đổi).
  • Giải pháp: Tìm ước lớn nhất của \(M\) mà không vượt quá \(\sqrt{M}\). Gọi ước đó là \(a\), số còn lại là \(b = M/a\).
  • Kết quả: \(a + b\).

2. Thuật toán chi tiết

  1. Đọc số nguyên \(N\).
  2. Nếu \(N = 0\), in ra \(0\) và kết thúc.
  3. Tính \(M = |N|\).
  4. Duyệt tìm \(a\) là ước lớn nhất của \(M\) trong đoạn \([1, \sqrt{M}]\).
  5. Tính \(b = M / a\).
  6. Nếu \(N > 0\): In ra \(b - a\).
  7. Nếu \(N < 0\): In ra \(b + a\).
    Độ phức tạp: \(O(\sqrt{|N|})\). Với \(|N| \le 10^{12}\), \(\sqrt{|N|} \le 10^6\), thuật toán chạy tốt trong giới hạn \(1\) giây.

3. Mã nguồn C++ hoàn chỉnh

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

int main() {
    // Toi uu toc do nhap xuat
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    long long n;
    if (!(cin >> n)) return 0;

    // Xu ly truong hop N = 0
    if (n == 0) {
        cout << 0 << endl;
        return 0;
    }

    // Lay gia tri tuyet doi de xu ly uoc so
    long long m = llabs(n);
    long long a = 1;

    // Tim uoc lon nhat <= can bac hai cua M
    long long root = sqrt((long double)m);
    for (long long i = root; i >= 1; i--) {
        if (m % i == 0) {
            a = i;
            break;
        }
    }

    long long b = m / a;

    // Xuat ket qua dua tren dau cua N
    if (n > 0) {
        // Neu N duong, a va b cung dau: |b - a|
        cout << b - a << endl;
    } else {
        // Neu N am, a va b trai dau: |a - (-b)| = a + b
        cout << a + b << endl;
    }

    return 0;
}

Bình luận

Mới nhất
Tải bình luận...

Không có bình luận nào.