You are on page 1of 8

Dynamic Programming level A

Bài 1: DP_A1

Dãy số Fibonacci được định nghĩa là:

 𝐹1 = 𝐹2 = 1;
 𝐹𝑖 = 𝐹𝑖−1 + 𝐹𝑖−2 (𝑖 ≥ 3).

Yêu cầu: Cho một số nguyên dương 𝑁, in ra 𝐹𝑁 𝑚𝑜𝑑 (109 + 7).

Input:

 Dòng đầu tiên gồm một số nguyên dương 𝑇- số lượng testcase (𝑇 ≤ 105 );
 𝑇 dòng tiếp theo, mỗi dòng gồm một số nguyên dương 𝑁 (𝑁 ≤ 106 ).

Output: In ra 𝑇 dòng tương ứng với kết quả của mỗi 𝑁 trong 𝑇 câu hỏi.

Ví dụ:

DP_A1.INP DP_A1.OUT
3 1
1 2
3 5
5

Lời giải

Đây là bài toán qui hoạch động cơ bản, chúng ta sẽ xây dựng toàn bộ mảng 𝐹[𝑖] với ý nghĩa là số
Fibonacci thứ 𝑖. Công thức được xây dựng:

 𝐹[1] = 𝐹[2] = 1;
 𝐹[𝑖] = (𝐹[𝑖 − 1] + 𝐹[𝑖 − 2]) % (109 + 7).

Ta sẽ chỉ cần xây dựng toàn bộ từ 𝐹[1] → 𝐹[106 ] là đủ vì ở đây 𝑁 của đề bài không bao giờ lớn
hơn 106 . Khi xây dựng sau, mỗi truy vấn chúng ta sẽ lấy ra 𝐹[𝑁] với độ phức tạp chỉ là 𝑂(1)
nên tổng độ phức tạp bài toán là 𝑂(106 + 𝑇).

Bài 2: DP_A2

Cho một dãy số nguyên gồm 𝑁 phần tử 𝑎1 , 𝑎2 , … , 𝑎𝑁 .

Yêu cầu: Tìm giá trị lớn nhất của (𝑎𝑗 − 𝑎𝑖 ) với 1 ≤ 𝑖 < 𝑗 ≤ 𝑁.
Input:

 Dòng đầu gồm duy nhất một số nguyên dương 𝑁 (𝑁 ≤ 106 );


 Dòng thứ hai gồm 𝑁 số nguyên 𝑎1 , 𝑎2 , … , 𝑎𝑁 (|𝑎𝑖 | ≤ 109 ).

Output: In ra kết quả bài toán.

Ví dụ:

DP_A2.INP DP_A2.OUT
7 11
8 2 4 -2 9 1 -3

Giải thích: (𝑖, 𝑗) = (4,5).

Lời giải

Chúng ta cần xây dựng mảng 𝐺[𝑖] với ý nghĩa 𝐺[𝑖] = min{𝑎1 , 𝑎2 , … , 𝑎𝑖 }. Ta sẽ xây dựng công
thức này như sau:

 𝐺[1] = 𝑎1 ;
 𝐺[𝑖] = min(𝐺[𝑖 − 1], 𝑎𝑖 ) (𝑖 ≥ 2).

Công thức trên có thể dễ dàng chứng minh được!

Từ đây, muốn tìm kết quả bài toán, ta chỉ việc so sách các giá trị (𝑎𝑗 − 𝐹[𝑗 − 1]) với 𝑗 = 2 → 𝑛
bởi vì rõ ràng nhận thấy giá trị (𝑎𝑗 − 𝑎𝑖 ) sẽ tốt hơn nếu 𝑎𝑖 = min{𝑎1 , 𝑎2 , … , 𝑎𝑗−1 } = 𝐹[𝑗 − 1].

Như vậy tổng độ phức tạp của bài toán này chỉ là 𝑂(𝑁).

Bài 3: DP_A3

Cho dãy số nguyên gồm 𝑁 phần tử 𝑎1 , 𝑎2 , … , 𝑎𝑁 .

Yêu cầu: Tìm giá trị lớn nhất của (𝑎𝑖 + 𝑎𝑗 − 𝑎𝑘 ) với 1 ≤ 𝑖 < 𝑗 < 𝑘 ≤ 𝑁.

Input:

 Dòng đầu gồm duy nhất một số nguyên dương 𝑁 (𝑁 ≤ 106 );


 Dòng thứ hai gồm 𝑁 phần tử 𝑎1 , 𝑎2 , … , 𝑎𝑁 (|𝑎𝑖 | ≤ 109 ).

Output: In ra kết quả bài toán.

Ví dụ:
DP_A3.INP DP_A3.OUT
7 20
8 2 4 -5 9 1 -3

Giải thích: (𝑖, 𝑗, 𝑘) = (1,5,7).

Lời giải

Tương tự như bài DP_A2 thì ở đây chúng ta cần thực hiện qui hoạch động hai mảng 𝑃𝑟𝑒[𝑖] =
𝑚𝑎𝑥{𝑎1 , 𝑎2 , … , 𝑎𝑖 } và 𝑆𝑢𝑓[𝑖] = min{𝑎𝑖 , 𝑎𝑖+1 , … , 𝑎𝑁 }. Sau đó ta chỉ việc so sánh các giá trị
(𝑃𝑟𝑒[𝑗 − 1] + 𝑎𝑗 − 𝑆𝑢𝑓[𝑗 + 1]) với 𝑗 = 2 → 𝑛 − 1. Đô phức tạp bài toán vẫn chỉ cỡ 𝑂(3𝑁).

Bài 4: DP_A4

Cho dãy số nguyên gồm 𝑁 phần tử 𝑎1 , 𝑎2 , … , 𝑎𝑁 .

Yêu cầu: Cho hay chỉ số 𝐿, 𝑅 (1 ≤ 𝐿 ≤ 𝑅 ≤ 𝑁). Hãy tính 𝑓(𝐿, 𝑅) = 𝑎𝐿 + 𝑎𝐿+1 + ⋯ + 𝑎𝑅 .

Input:

 Dòng đầu gồm duy nhất một số nguyên dương 𝑁 (𝑁 ≤ 105 );


 Dòng thứ hai gồm 𝑁 số nguyên 𝑎1 , 𝑎2 , … , 𝑎𝑁 (|𝑎𝑖 | ≤ 109 );
 Dòng thứ ba gồm một số nguyên dương 𝑇 − số lượng testcase (𝑇 ≤ 105 );
 𝑇 dòng tiếp, mỗi dòng gồm một cặp số nguyên dương 𝐿, 𝑅 (1 ≤ 𝐿 ≤ 𝑅 ≤ 𝑁).

Output: In ra 𝑇 dòng, mỗi dòng là 𝑓(𝐿, 𝑅) tương ứng.

Ví dụ:

DP_A4.INP DP_A4.OUT
5 6
8 2 -4 3 1 3
3 0
13
44
35

Lời giải

Ta sẽ xây dựng một mảng 𝑆𝑢𝑚[𝑖] = 𝑎1 + 𝑎2 + ⋯ + 𝑎𝑖 (1 ≤ 𝑖 ≤ 𝑁). Ta sẽ xây dựng như sau:

 𝑆𝑢𝑚[0] = 0;
 𝑆𝑢𝑚[𝑖] = 𝑆𝑢𝑚[𝑖 − 1] + 𝑎𝑖 (1 ≤ 𝑖 ≤ 𝑁).
Như vậy, với mỗi truy vấn (𝐿, 𝑅) ta sẽ in ra giá trị (𝑆𝑢𝑚[𝑅] − 𝑆𝑢𝑚[𝐿 − 1]) chính là kết quả
của chúng ta cần tìm.

Bài 5: DP_A5

Cho một dãy số nguyên gồm 𝑁 phần tử 𝑎1 , 𝑎2 , … , 𝑎𝑁 . Gọi 𝑓(𝐿, 𝑅) = 𝑎𝐿 + 𝑎𝐿+1 + ⋯ +


𝑎𝑅 (1 ≤ 𝐿 ≤ 𝑅 ≤ 𝑁).

Yêu cầu: Tìm giá trị 𝑓(𝐿, 𝑅) lớn nhất.

Input:

 Dòng đầu gồm duy nhất một số nguyên dương 𝑁 (𝑁 ≤ 106 );


 Dòng tiếp theo gồm 𝑁 số nguyên 𝑎1 , 𝑎2 , … , 𝑎𝑁 (|𝑎𝑖 | ≤ 109 ).

Output: In ra kết quả bài toán.

Ví dụ:

DP_A5.INP DP_A5.OUT
5 9
6 -4 5 2 -1

Lời giải

Ta tiếp tục xây dựng mảng 𝑆[𝑖] = 𝑎1 + 𝑎2 + ⋯ + 𝑎𝑖 . Khi đó, 𝑓(𝐿, 𝑅) = 𝑆[𝑅] − 𝑆[𝐿 − 1], tức là
ta cần tìm giá trị 𝑓(𝑖, 𝑗) lớn nhất mà 𝟎 ≤ 𝒊 < 𝒋 ≤ 𝑵 hay giá trị 𝑆[𝑗] − 𝑆[𝑖] lớn nhất. Điều này đưa
chúng ta về giống như bài toán DP_A1, như vậy độ phức tạp của bài toán vẫn chỉ là 𝑂(𝑁).

Bài 6: DP_A6

Cho dãy số nguyên gồm 𝑁 phần tử 𝑎1 , 𝑎2 , … , 𝑎𝑁 .

Yêu cầu: Chọn ra một tập gồm các phần tử trong dãy (tập hợp có thể rỗng) sao cho không có hai
phần tử nào kề nhau và có tổng các số trong tập hợp là lớn nhất có thể. In ra tổng của tập hợp tìm
được (nếu là tập rỗng thì tổng bằng 0).

Input:

 Dòng đầu gồm duy nhất một số nguyên dương 𝑁 (𝑁 ≤ 105 );


 Dòng thứ hai gồm 𝑁 phần tử 𝑎1 , 𝑎2 , … , 𝑎𝑁 (|𝑎𝑖 | ≤ 109 ).

Output: In ra kết quả bài toán.

Ví dụ:

DP_A6.INP DP_A6.OUT
3 10
456

Lời giải

Ta sẽ gọi 𝐹[𝑖] chính là kết quả của bài toán trên dãy số 𝑎1 , 𝑎2 , … , 𝑎𝑖 . Khi đó ta sẽ có công thức
như sau:

 𝐹[1] = max(0, 𝑎1 ) ;
 𝐹[2] = max(0, 𝑎1 , 𝑎2 ) ;
 𝐹[𝑖] = max(𝐹[𝑖 − 2] + 𝑎𝑖 , 𝐹[𝑖 − 1]) (𝑖 ≥ 3).

Ở đây, để xây dựng 𝐹[𝑖] thì chúng ta có hai loại, là ta có thể thêm 𝑎𝑖 vào tập hợp hay không?
Nếu thêm 𝑎𝑖 vào tập hợp thì chắc chắn không được thêm 𝑎𝑖−1 và do đó kết quả tốt nhất là
𝐹[𝑖 − 2] + 𝑎𝑖 , tức là tập hợp có tổng lớn nhất trong dãy {𝑎1 , 𝑎2 , … , 𝑎𝑖−2 } và sau đó là bổ sung 𝑎𝑖
vào tập. Còn nếu không chọn 𝑎𝑖 thì hiển nhiên ta sẽ lấy 𝐹[𝑖 − 1]. Do đó ta chỉ cần xem xem các
nào có tổng lớn nhất thì ta sẽ chọn cách đó. Kết quả bài toán chính là 𝐹[𝑁] và độ phức tạp bài
toán tất nhiên là 𝑂(𝑁).

Bài 7: DP_A7

Một 𝑆 được gọi là xâu con của xâu 𝑇 nếu như bỏ đi một số kí tự trên xâu 𝑇 sẽ thu được xâu 𝑆. Ví
dụ xâu 𝑇 = 𝑎𝑏𝑐𝑥𝑦𝑧 thì xâu 𝑆 = 𝑎𝑐𝑦𝑧 là xâu con của xâu 𝑇 còn xâu 𝑆 ′ = 𝑎𝑐𝑦𝑥𝑧 thì không phải.
Xâu rỗng là xâu con của mọi xâu.

Yêu cầu: Cho trước hai xâu 𝐴 và 𝐵 chỉ gồm các chữ cái latin thường, tìm xâu 𝐶 dài nhất thỏa
mãn 𝐶 đều là xâu con của 𝐴 và 𝐵, in ra độ dài xâu 𝐶. Nếu xâu 𝐶 rỗng thì in ra 0.

Input:

 Dòng đầu gồm xâu 𝐴 (|𝐴| ≤ 3000);


 Dòng thứ hai gồm xâu 𝐵 (|𝐵| ≤ 3000);
Kí hiệu |𝑆| là độ dài xâu 𝑆 nào đó.

Output: In ra kết quả bài toán..

Ví dụ:

DP_A7.INP DP_A7.OUT
abyzux 4
buyzox
Giải thích: xâu 𝐶 = 𝑏𝑦𝑧𝑥.

Lời giải

Trước hết, đánh số các kí tự của một xâu 𝑆 bất kì từ 1 → |𝑆| từ trái sang phải.

Gọi 𝐹[𝑖][𝑗] là kết quả của bài toán của hai xâu 𝐴[1 … 𝑖] và 𝐵[1 … 𝑗]. Ở đây ta có thể thêm 𝐴[𝑖]
vào 𝐶 hoặc thêm 𝐵[𝑗] vào xâu 𝐶 do đó được xây dựng là: 𝐹[𝑖][𝑗] = max(𝐹[𝑖 − 1][𝑗], 𝐹[𝑖][𝑗 −
1]). Nếu 𝐴[𝑖] = 𝐵[𝑗] thì ta có thể thêm kí tự 𝐴[𝑖] vào kí tự 𝐶, khi đó công thức 𝐹[𝑖][𝑗] =
𝐹[𝑖 − 1][𝑗 − 1] + 1. Do đó, khi 𝐴[𝑖] = 𝐵[𝑗] thì 𝐹[𝑖][𝑗] = max(𝐹[𝑖 − 1][𝑗], 𝐹[𝑖][𝑗 − 1], 𝐹[𝑖 −
1][𝑗 − 1] + 1). Như vậy kết quả bài toán sẽ chính là 𝐹[ |𝐴| ][ |𝐵| ]. Độ phức tạp của bài toán
chính là 𝑂(|𝐴|. |𝐵|).

Bài 8: DP_A8

Cho dãy số nguyên dương gồm 𝑁 phần tử 𝑎1 , 𝑎2 , … , 𝑎𝑁 .

Yêu cầu: Đếm số lượng cặp chỉ số (𝑖, 𝑗) thỏa mãn 𝑎𝑖 + 𝑎𝑗 = 𝑋 và 1 ≤ 𝑖 ≤ 𝑗 ≤ 𝑁.

Input:

 Dòng đầu gồm hai số nguyên dương 𝑁 và 𝑋 (𝑁, 𝑋 ≤ 105 );


 Dòng thứ hai gồm 𝑁 phẩn tử nguyên dương 𝑎1 , 𝑎2 , … , 𝑎𝑁 (𝑎𝑖 ≤ 106 ).

Output: In ra kết quả bài toán.

Ví dụ:

DP_A8.INP DP_A8.OUT
3 7
123 1
234
537

Lời giải

Ta sẽ dùng mảng 𝐶𝑁𝑇[𝑋] với ý nghĩa là số lượng phần tử thuộc dãy 𝐴 có giá trị là 𝑋. Xây dựng
hàm 𝐶𝑁𝑇 khá đơn giản: 𝑓𝑜𝑟(𝑖𝑛𝑡 𝑖 = 1; 𝑖 ≤ 𝑛; + + 𝑖) 𝐶𝑁𝑇[𝑎[𝑖]] + +;

Sau khi đó được hàm 𝐶𝑁𝑇[𝑋], ta sẽ tiếp tục dùng vòng for, xem giá trị 𝑎𝑖 là 𝑥 thì giá trị 𝑎𝑗 =
𝑋 − 𝑥. Nên ở đây ta sẽ for các giá trị có thể của 𝑥 cụ thể là for 𝑥 từ 1 → 𝑋 sau đó lấy 𝑦 = 𝑋 − 𝑥
và thêm vào kết quả một lượng là 𝐶𝑁𝑇[𝑥] ∗ 𝐶𝑁𝑇[𝑦]. Như vậy độ phức tạp bài toán là 𝑂(𝑋 + 𝑁).

Bài 9: DP_A9
Cho bảng số gồm 𝑀 hàng và 𝑁 cột, hàng thứ 𝑖 cột thứ 𝑗 của bảng số gọi là ô (𝑖, 𝑗) có giá trị 𝑎𝑖,𝑗 .
Cho 4 số nguyên dương 𝑥1 , 𝑦1 , 𝑥2 , 𝑦2 (1 ≤ 𝑥1 ≤ 𝑥2 ≤ 𝑀; 1 ≤ 𝑦1 ≤ 𝑦2 ≤ 𝑁).

Yêu cầu: Tính tổng các giá trị của các ô nằm trên hình chữ nhật có góc trái trên là ô (𝑥1 , 𝑦1 ) và
góc phải dưới là ô (𝑥2 , 𝑦2 ).

Input:

 Dòng đầu gồm hai số nguyên dương 𝑀 và 𝑁 (1 ≤ 𝑀, 𝑁 ≤ 1000);


 Trong 𝑀 dòng tiếp theo, dòng thứ 𝑖 gồm 𝑁 số nguyên 𝑎𝑖1 , 𝑎𝑖2 , … , 𝑎𝑖𝑁 (|𝑎𝑖𝑗 | ≤ 100);
 Dòng tiếp theo gồm duy nhất một số nguyên dương 𝑇 − số lượng câu hỏi (𝑇 ≤ 104 );
 𝑇 dòng sau, mỗi dòng gồm 4 số nguyên dương 𝑥1 , 𝑦1 , 𝑥2 , 𝑦2 (1 ≤ 𝑥1 ≤ 𝑥2 ≤ 𝑀; 1 ≤
𝑦1 ≤ 𝑦2 ≤ 𝑁).

Output: In ra 𝑇 dòng, mỗi dòng là tổng các giá trị của các ô nằm trên hình chữ nhật có góc trái
trên là ô (𝑥1 , 𝑦1 ) và góc phải dưới là ô (𝑥2 , 𝑦2 ) tương ứng.

Ví dụ:

DP_A9.INP DP_A9.OUT
23 8
123 12
234
2
1122
1223

Lời giải

Ta gọi 𝑓[𝑖][𝑗] là tổng các giá trị nằm trên hình chữ nhật có góc trái trên là ô (1,1) và có góc phải
dưới là ô (𝑖, 𝑗). Ban đầu ta cho toàn bộ mảng 𝑓 = 0. Sau đó thì ta sẽ xây dựng theo công thức
𝑓[𝑖][𝑗] = 𝑓[𝑖 − 1][𝑗] + 𝑓[𝑖][𝑗 − 1] − 𝑓[𝑖 − 1][𝑗 − 1] + 𝑎[𝑖][𝑗]. Sau đó thì để tính tổng các giá
trị của một hình chữ nhật có góc trái trên là ô (𝑥1 , 𝑦1 ) và góc phải dưới là ô (𝑥2 , 𝑦2 ) thì ta tiếp
tục có công thức: 𝑓[𝑥2 ][𝑦2 ] − 𝑓[𝑥1 − 1][𝑦2 ] − 𝑓[𝑥2 ][𝑦1 − 1] + 𝑓[𝑥1 − 1][𝑦1 − 1]. Do đó ta có
thể xây dựng công thức quy hoạch động với độ phức tạp 𝑂(𝑀. 𝑁) nhưng với mỗi truy vấn ta có
thể đưa ra kết quả với độ phức tạp 𝑂(1). Từ đó, độ phức tạp cho bài toán là 𝑂(𝑀. 𝑁 + 𝑇).

Bài 10: DP_A10

Cho bảng số gồm 𝑀 hàng và 𝑁 cột, hàng thứ 𝑖 cột thứ 𝑗 của bảng số gọi là ô (𝑖, 𝑗) có giá trị 𝑎𝑖,𝑗 .
Một con ROBOT nếu đặt trên bảng số tại ô (𝑖, 𝑗) thì nó chỉ có thể đi đến ô (𝑖 + 1, 𝑗) hoặc ô
(𝑖, 𝑗 + 1).
Yêu cầu: Giả sử đặt con ROBOT ban đầu tại ô (1,1). Hãy tìm đường đi từ ô (1,1) đến ô (𝑀, 𝑁)
sao cho giá trị đường đi của ROBOT là lớn nhất. Giá trị của một đường đi là tổng các giá trị của
các ô nằm trên đường đi đó (bao gồm cả ô (1,1) và ô (𝑀, 𝑁)).

Input:

 Dòng đầu gồm hai số nguyên dương 𝑀 và 𝑁 (𝑀, 𝑁 ≤ 3000);


 𝑀 dòng tiếp theo mỗi dòng gồm 𝑁 số nguyên 𝑎𝑖1 , 𝑎𝑖2 , … , 𝑎𝑖𝑁 (|𝑎𝑖𝑗 | ≤ 100);

Output: In ra giá trị của đường đi tìm được.

Ví dụ:

DP_A10.INP DP_A10.OUT
33 16
123
2 3 -4
-5 3 7

Lời giải

Gọi 𝑓[𝑖][𝑗] là đường đi có giá trị lớn nhất khi xuất phát từ ô (1,1) và hiện tại đang ở ô (𝑖, 𝑗). Để
đến được ô (𝑖, 𝑗) thì chúng ta có thể đi từ ô (𝑖 − 1, 𝑗) hoặc ô (𝑖, 𝑗 − 1) sang, do đó cho nên công
thức quy hoạch động sẽ là: 𝑓[𝑖][𝑗] = max(𝑓[𝑖 − 1][𝑗], 𝑓[𝑖][𝑗 − 1]) + 𝑎[𝑖][𝑗]. Khởi tạo đó chính
là 𝑓[1][1] = 𝑎[1][1].

Độ phức tạp cho bài toán này là 𝑂(𝑀. 𝑁).

You might also like