Hướng dẫn cho GCDSUM


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: NghiaUwU

Rất cảm ơn bạn NghiaUwU đã đóng góp solution cho bài tập này.

Trong bài này thì ta áp dụng kiến thức Ước chung lớn nhất (còn gọi là GCD - Greatest Common Divisor trong tiếng anh) và ở đây số khá nhỏ \((n \le 10^5)\) nên ở đây mình có thể chạy \(for\) đồng thời sử dụng 1 trong 2 cách sau đây để giải quyết (trong đó cách \(2\) sẽ giúp các bạn AC) bao gồm đệ quy tìm \(GCD\) và sử dụng hàm trong \(C++\).

Cách 1. Đệ quy

Để cụ thể và dễ hiểu thì mình sẽ cho \(2\) số là \(a\)\(b\), trong đó \(a\) bé hơn \(b\).
Theo lí thuyết, nếu ta trừ số lớn cho số bé hơn (hay \(b – a\)) thì ước chung lớn nhất của nó không thay đổi (\(GCD (a, b) = GCD (a, b – a)\)) \(→\) Từ đó, nếu ta cứ đệ quy trừ số lớn cho số bé thì ta sẽ được GCD của hai số đó.
Cũng chính cách đó nhưng nếu ta đệ quy trừ sẽ dẫn đến \(TLE\) nên ta có thể thay phép trừ bằng phép chia ( cụ thể là \(a : b\)) và bằng cách này ngoài tránh \(TLE\) mà kết quả cũng như vậy.

Nhưng trong lúc làm, mình phát hiện cách này có lúc bị WA, có lúc bị RTE tại một số bài làm và cả bài của mình trước khi AC nên mình thấy cách làm này chỉ được 6 / 8 thôi UwU.

C++
int gcd(int a, int b)
{
    if (a == 0)
    return b;
    return gcd(b % a, a);
}

Đệ quy bị WA.

C++
ll ucln(ll a,ll b)
{
    ll temp;
    while(b>0)
    {
        temp=a;
        a=b;
        b=temp%b;
    }
    return a;
}

Đệ quy bị RTE.


Cách 2

Thì dành cho ai chưa biết thì trong C++ có một hàm mang tên __gcd() thuộc thư viện algorithm, cú pháp là __gcd(a, b)(ở đây __gcd(i * i, n))

Lưu ý: \(a\)\(b\) phải cùng kiểu dữ liệu như int hoặc long long.
Link cho các bạn tìm hiểu về hàm ___gcd():

https://www.geeksforgeeks.org/stdgcd-c-inbuilt-function-finding-gcd/

Bằng hàm __gcd() này thì việc còn lại của bạn là chạy \(for\), tìm \(GCD\) của (\(i * i\)\(n\)) rồi cộng kết quả đó vào tổng của từng số.

Bonus: Nếu \(n\) chia hết cho \(i * i\) thì \(t\) có thể cộng thẳng \(i * i\) vào trong tổng rồi sử dụng lệnh continue để chạy tiếp vòng \(for\).



Bình luận


  • 3
    VoBaThongL921    10:15 a.m. 30 Tháng 11, 2021

    bruh cái hàm ucln bị rte đó do mấy ông for i từ 1 đến n mà xài int, với n = 1e5 thì i = 1e10 int ko chứa nổi thì bị rte:D

    2 phản hồi