Không hỗ trợ Mobile

Chế độ luyện tập yêu cầu môi trường màn hình lớn để làm bài và chống gian lận hiệu quả. Vui lòng truy cập bằng máy tính (Desktop/Laptop) để tiếp tục thao tác.

Quay lại trang chủ

#1073 · Xâu tam phân

MÔ TẢ BÀI TOÁN

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.

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
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
2 ms 288 KB
635 Bytes
01/04/2024
10:54
5
2 ms 308 KB
651 Bytes
13/09/2025
21:21
6
3 ms 224 KB
833 Bytes
28/12/2025
00:41
7
L
3 ms 288 KB
445 Bytes
29/08/2024
21:04
8
3 ms 292 KB
495 Bytes
16/02/2025
23:10
9
H
3 ms 292 KB
595 Bytes
03/12/2023
22:10
10
P
3 ms 304 KB
485 Bytes
17/12/2025
17:03
11
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
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
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
4 ms 976 KB
349 Bytes
15/03/2024
23:27
18
4 ms 1036 KB
290 Bytes
31/03/2024
21:37
19
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
20 ngày trước

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

ans(2,0)

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

Viết code