Một xâu được gọi xâu tam phân nếu xâu đó chỉ tồn tại các kí tự 0, 1, 2. Hãy đếm số lượng xâu tam phân độ dài n mà không có 2 kí tự 1 liền kề nhau.
MÔ TẢ BÀI TOÁN
Dữ liệu vào
Dòng đầu là một số nguyên n (1 \leq n \leq 10^5)
Dữ liệu ra
In ra một dòng là số lượng xâu thoả mãn. Kết quả có thể lớn, hãy đưa ra kết quả theo phần dư của 10^9+ 7
BẢNG TỔNG QUAN KẾT QUẢ
| # | Tài khoản | Kết suất | Lúc nộp |
|---|---|---|---|
| 1 |
Lê Duy Hải
@2280600799
|
2 ms
224 KB
478 Bytes
|
17/05/2025 12:31 |
| 2 |
K
Nguyễn Võ Lê Khoa
@2380601073
|
2 ms
224 KB
602 Bytes
|
19/05/2025 11:23 |
| 3 |
B
Trần Gia Bảo
@2380600172
|
2 ms
224 KB
1011 Bytes
|
01/10/2024 20:45 |
| 4 |
C
Dương Thành Công
@2280618984
|
2 ms
288 KB
635 Bytes
|
01/04/2024 10:54 |
| 5 |
T
Nguyễn Trung Tuyến
@2011064511
|
2 ms
308 KB
651 Bytes
|
13/09/2025 21:21 |
| 6 |
Sơn Trung Chiến
@25800600077
|
3 ms
224 KB
833 Bytes
|
28/12/2025 00:41 |
| 7 |
L
Nhan Huỳnh Lâm
@2387700037
|
3 ms
288 KB
445 Bytes
|
29/08/2024 21:04 |
| 8 |
Q
Nguyễn Phan Hoàng Quân
@2280602604
|
3 ms
292 KB
495 Bytes
|
16/02/2025 23:10 |
| 9 |
H
Ngô Mạnh Hùng
@2280601102
|
3 ms
292 KB
595 Bytes
|
03/12/2023 22:10 |
| 10 |
P
Lương Hoài Phong
@2287700062
|
3 ms
304 KB
485 Bytes
|
17/12/2025 17:03 |
| 11 |
C
Lê Phạm Hùng Cường
@2280600343
|
3 ms
304 KB
716 Bytes
|
30/09/2025 19:51 |
| 12 |
H
Võ Minh Hiển
@24800600298
|
3 ms
992 KB
305 Bytes
|
23/10/2024 22:22 |
| 13 |
H
Nguyễn Hoàng Huy
@2380612877
|
3 ms
992 KB
305 Bytes
|
31/12/2024 04:22 |
| 14 |
Lê Duy Hải
@2280600799
|
3 ms
1060 KB
388 Bytes
|
17/05/2025 12:29 |
| 15 |
V
Trần Nguyên Vũ
@24800609016
|
3 ms
2568 KB
556 Bytes
|
09/04/2026 01:18 |
| 16 |
H
Võ Thanh Hà
@2280600789
|
4 ms
288 KB
406 Bytes
|
25/04/2024 20:50 |
| 17 |
P
GV. Nguyễn Trọng Minh Hồng Phước
@PNTM020597
|
4 ms
976 KB
349 Bytes
|
15/03/2024 23:27 |
| 18 |
S
Nguyễn Võ Hoàng Sơn
@2280618566
|
4 ms
1036 KB
290 Bytes
|
31/03/2024 21:37 |
| 19 |
P
Nguyễn Đại Phát
@2380601627
|
4 ms
1804 KB
567 Bytes
|
06/07/2024 17:53 |
| 20 |
Lê Duy Hải
@2280600799
|
5 ms
1832 KB
1138 Bytes
|
23/02/2024 11:17 |
LỊCH SỬ CÁ NHÂN
Vui lòng đăng nhập để xem lịch sử làm bài của bạn.
THẢO LUẬN BÀI TOÁN
V
Trần Nguyên Vũ
@24800609016
aaa
Ta gọi:
f(n) là số xâu có độ dài n không chứa 11 liền kề.
Để tạo công thức truy hồi đầy đủ ta sẽ dùng phương pháp ghép chữ số ở cuối dãy f(n)
Để đơn giản hóa thì ta sẽ biến đổi lại f(n) thành f(n, c) thì trong đó c là chữ số ghép tại vị trí a(n)
Vậy ta sẽ có 3 TH như sau:
TH1: c = 0
f(n, 0) = a(1)a(2)...a(n-2)a(n-1)0
Nếu a(n-1) = 0,1,2 thì đều thỏa mãn vì không chứa 11
=> số xâu thỏa f(n, 0) = f(n-1, 0) + f(n-1, 1) + f(n-1, 2)
TH2: c = 2 (tương tự với c = 0)
=> số xâu thỏa f(n, 2) = f(n-1, 0) + f(n-1, 1) + f(n-1, 2)
TH3: c = 1
f(n, 0) = a(1)a(2)...a(n-2)a(n-1)1
Nếu a(n-1) = 0,2 (loại c=1 vì liền kề 11) thì đều thỏa mãn vì không chứa 11
=> số xâu thỏa f(n, 1) = f(n-1, 0) + f(n-1, 2)
Suy ra công thức đầy đủ là:
f(n, c) = f(n, 0) + f(n, 1) + f(n, 2)
Trong đó:
f(n, 0) = f(n-1, 0) + f(n-1, 1) + f(n-1, 2)
f(n, 1) = f(n-1, 0) + f(n-1, 2)
f(n, 2) = f(n-1, 0) + f(n-1, 1) + f(n-1, 2)
Tiếp theo là tới basecase:
Với n = 1 (xâu 1 ký tự) thì tất cả đều hợp lệ:
=> f(1, c) = 1 (ở đây có 1 xâu thõa mãn)
Vậy ta có thể code đơn giản như sau:
#include <iostream>
#define ll long long
#define MAX 1000000
#define MOD 1000000007
using namespace std;
// Ở đây chưa thêm MOD đâu :v
ll ans(ll n, int c)
{
if(n == 1) return 1;
if(c == 0 || c == 2) // TH 1 và 2
return ans(n-1, 0) + ans(n-1, 1) + ans(n-1, 2);
else if(c == 1) // TH 3
return ans(n-1, 0) + ans(n-1, 2);
}
int main() {
ll n;
cin >> n;
// Tương đương: f(n, c) = f(n, 0) + f(n, 1) + f(n, 2)
cout << ans(n, 0) + ans(n, 1) + ans(n, 2);
return 0;
}
Ta có công thức truy hồi, code chạy ra => Dùng quy hoạch động.
Đơn giản là ta chỉ lưu trữ để tránh tính toán lại thôi
Code:
#include <iostream>
#define ll long long
#define MAX 1000000
#define MOD 1000000007
using namespace std;
ll dp[MAX+1][3];
ll ans(ll n, int c)
{
if(n == 1) return 1;
if(dp[n][c] != -1) return dp[n][c]; // Trả về luôn nếu có trong dp
if(c == 0 || c == 2)
dp[n][c] = ans(n-1, 0) + ans(n-1, 1) + ans(n-1, 2);
else if(c == 1)
dp[n][c] = ans(n-1, 0) + ans(n-1, 2);
return dp[n][c];
}
int main() {
// Khởi tạo dp
for(int i=0; i<=MAX; i++)
for(int j=0; j<=2; j++)
dp[i][j] = -1;
ll n;
cin >> n;
cout << ans(n, 0) + ans(n, 1) + ans(n, 2);
return 0;
}
Dùng đệ quy thì dễ bị tràn stack. Thế nên ta sẽ xây từ basecase lên đỉnh
Code:
#include <iostream>
#define ll long long
#define MAX 1000000
#define MOD 1000000007
using namespace std;
ll dp[MAX+1][3];
ll ans(ll n)
{
dp[1][0] = 1;
dp[1][1] = 1;
dp[1][2] = 1;
for(int i=2; i<=n; i++){
dp[i][0] = dp[i-1][0] + dp[i-1][1] + dp[i-1][2];
dp[i][1] = dp[i-1][0] + dp[i-1][2];
dp[i][2] = dp[i-1][0] + dp[i-1][1] + dp[i-1][2];
}
return dp[n][0] + dp[n][1] + dp[n][2];
}
int main() {
ll n;
cin >> n;
cout << ans(n);
return 0;
}
Ok nhớ thêm MOD để được AC nhé :))
Cây đệ quy với testcase n = 2
Trong ví dụ này có 8 xâu là: 00, 01, 02, 10, 12, 20, 21, 22
Tóm lại là ta chỉ né 1 ra nếu trước đó là 1 :)))
Vào thảo luận
0 Phản hồi
GỢI Ý & HƯỚNG DẪN
Trong ví dụ thứ nhất có 8 xâu: 00, 01, 02, 10, 12, 20, 21, 22


