Số Lặp Lại (CPP0181)
Đề bài
SỐ LẶP LẠI
Cho ba số $a$, $x$, $y$. Nhiệm vụ của bạn là tìm ước số chung lớn nhất của hai số $P$ và $Q$, trong đó $P$ lặp lại $x$ lần số $a$ và $Q$ lặp lại $y$ lần số $a$. Ví dụ $a = 2$, $x = 3$, $y = 2$ thì $P = 222$, $Q = 22$.
Input:
- Dòng đầu tiên đưa vào $T$ là số lượng bộ test.
- $T$ dòng tiếp theo đưa các bộ test. Mỗi bộ test được viết trên một dòng là bộ ba số $a$, $x$, $y$ phân biệt nhau bởi một vài khoảng trống.
- Các số $T$, $a$, $x$, $y$ thoả mãn ràng buộc: $1 \le T \le 100$; $1 \le a, x, y \le 10^{18}$.
Output:
- Đưa ra kết quả mỗi test theo từng dòng.
Giới hạn thời gian: 2s. Giới hạn bộ nhớ: 65536 Kb.
2
2 2 3
123 5 22
123Lời mở đầu
Bài này là một bạn nhắn tin nhờ mình xem giúp code. Bạn ấy biết code mình bị lỗi do tràn dữ liệu nhưng chưa biết hướng giải quyết, sửa bằng chuỗi thì chưa nhuần nhuyễn nên thấy khó. Mình chia sẻ lại đoạn trao đổi thành bài giải này, vì cái hay của bài không nằm ở code (code chỉ vài dòng), mà nằm ở cách mình nhìn ra bản chất của bài toán. Các bạn thử sức tự làm trước rồi hãy đọc tiếp nhé 😉.
Bạn nào muốn thử nộp bài để hệ thống chấm xem có đúng hay không thì link bài đây nhé:
Bấm vào nút bên dưới để nộp bài và được hệ thống CLUE OJ chấm tự động.
Nộp bài trên CLUE OJGiải thích ví dụ:
- Test 1: $a = 2$, $x = 2$, $y = 3$ ⇒ $P = 22$, $Q = 222$. $\gcd(22, 222) = 2$ (vì $22 = 2 \cdot 11$, $222 = 2 \cdot 3 \cdot 37$) ⇒ in 2.
- Test 2: $a = 123$, $x = 5$, $y = 2$ ⇒ $P = 123123123123123$, $Q = 123123$. $\gcd(P, Q) = 123$ ⇒ in 123.
Lộ trình lời giải, bấm vào từng phần để nhảy tới:
Cách 1Số a lặp lại gcd(x, y) lần – O(log(min(x, y)) + độ dài kết quả)
Vì sao hướng "tạo ra số P, Q rồi tìm UCLN" không ổn?
Code của bạn học viên đi theo hướng rất tự nhiên: viết hàm tạo ra số lặp lại (nhân với $10^{\text{số chữ số của } a}$ rồi cộng $a$, lặp nhiều lần), sau đó tìm UCLN. Bạn ấy cũng đã nhìn ra đúng tư tưởng là có đi tìm UCLN của $x$, $y$. Nhưng sau đó, thay vì chỉ đơn giản là lặp lại in ra đủ bấy nhiêu lần số $a$, thì bạn lại đi xử lý để tạo ra một con số duy nhất rồi mới in, như thế rõ là không ổn:
(int)pow(10, num(a)) cũng tràn ngay khi $a$ có từ 10 chữ số trở lên.Em nhìn vào đề bài tập, nó có nói rõ dạng bài nè: bài nằm trong nhóm "Lập trình C++ cơ bản", chủ đề con "Kiểu dữ liệu – Viết vòng lặp – Viết hàm". Có cái nào là xử lý chuỗi hay xử lý số lớn đâu ^^ nên rõ là mình đang suy nghĩ phức tạp rồi 🙂.
Bám theo ví dụ để tìm quy luật
Thực ra mình cũng chẳng đi tính công thức toán học chứng minh gì nhiều đâu, mình cứ bám theo ví dụ đề cho, như số $123$, rồi thử nghiệm:
- Lấy $123123123123123123$ (lặp lại 6 lần), thử chia cho $123$ lặp lại 1, 2, 3, 4, 5 lần.
- Tự nhiên nhìn ra: bản chất nó sẽ chia hết cho những số lần lặp mà 6 chia hết được. $6$ chia hết cho $1, 2, 3, 6$, vậy nghĩa là $123$ lặp lại $1, 2, 3, 6$ lần thì $123123123123123123$ (6 lần lặp lại) sẽ chia hết; còn lặp 4 lần, 5 lần thì không.
- Thử thêm vài số nữa, thấy quy luật đúng :))).
Từ đó ta sẽ nhìn ra rõ bản chất: cứ 2 số $x$, $y$ là số lần lặp lại, tìm ra ước chung lớn nhất của tụi nó, rồi sau đó cho số $a$ lặp lại nhiêu đó lần là xong!
Minh hoạ
Em nhập $a$, $x$, $y$ rồi bấm Tiếp. Mỗi ô là một khối số $a$; mỗi bước ta "cắt" phần trùng với số nhỏ hơn ra khỏi số lớn hơn, UCLN không đổi:
Source code để các bạn tham khảo nếu làm theo hướng này (code này đã AC bài đó):
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin >> t;
while(t--)
{
long long a, x, y;
cin >> a >> x >> y;
long long res = __gcd(x, y);
for(long long i = 1; i <= res; ++i)
cout << a;
cout << endl;
}
return 0;
}
from math import gcd
t = int(input())
for _ in range(t):
a, x, y = map(int, input().split())
res = gcd(x, y)
print(str(a) * res)
Đánh giá độ phức tạp của cách làm này:
- Không gian: chỉ vài biến ⇒ $O(1)$.
- Thời gian: tìm UCLN bằng Euclid mất $O(\log(\min(x, y)))$, cộng với thời gian in kết quả $O(\gcd(x, y))$ lần in. Phần in là bắt buộc, vì đáp án dài chừng đó thì phải in chừng đó, không cách nào nhanh hơn được.
- Không biết học gì trước, học gì sau, học lan man nên kiến thức bị hổng.
- Bí bài không ai gỡ, ngồi cả buổi vẫn không ra rồi bỏ cuộc.
- Code chạy được nhưng không đủ điểm, không biết sai ở đâu, chậm ở đâu.
- Không có đề thi thử và người chấm, nên không biết mình đang ở mức nào.
- Dễ nản giữa chừng khi không có ai theo sát.
- Lộ trình 111 buổi video sắp sẵn từ dòng code đầu tiên đến đề HSG thật của các tỉnh.
- Thầy trực tiếp gỡ bí, chữa bài cho từng em qua nhóm Zalo riêng.
- Hệ thống chấm bài tự động 24/7 và thi thử HSG hằng tuần để biết chính xác mình đang ở đâu.
- Đóng học phí một lần, thầy kèm lâu dài: từ thi chuyên Tin đến HSG quốc gia và cả khi lên đại học.
Nhận xét
Đăng nhận xét