Tải bản đầy đủ (.pdf) (53 trang)

Hướng dẫn một số bài trên SPOJ

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.24 MB, 53 trang )

CÁC BÀI TOÁN DUYỆT

1. Robot quét vôi ( )
Có 9 căn phòng (đánh số từ 1 đến 9) đã được quét vôi với màu trắng, xanh hoặc vàng. Có 9 robot
(đánh số từ 1 đến 9) phụ trách việc quét vôi. Mỗi robot chỉ quét một số phòng nhất định. Việc
quét vôi được thực hiện nhờ một chương trình cài sẵn theo qui tắc:
Nếu phòng đang có màu trắng thì quét màu xanh
Nếu phòng đang có màu xanh thì quét màu vàng
Nếu phòng đang có màu vàng thì quét màu trắng
Cần phải gọi lần lượt một số các robot ra quét vôi (mỗi lần một robot, một robot có thể gọi nhiều
lần và có thể có robot không được gọi. Robot được gọi sẽ quét vôi tất cả các phòng mà nó phụ
trách) để cuối cùng các phòng đều có màu trắng.

Yêu cầu: Hãy tìm một phương án như vậy sao cho số lần gọi robot là ít nhất. Giả thiết rằng lượng
vôi cho mỗi lượt quét đối với các phòng là như nhau.

Input
9 dòng đầu: dòng thứ i mô tả một danh sách các phòng do robot i phụ trách việc quét vôi.
Mỗi dòng là một chuỗi các chữ số từ 1 9 biểu diễn các số hiệu của các phòng, các chữ số
viết sát nhau.
Dòng cuối mô tả mầu vôi ban đầu của các phòng. Dòng gồm 9 ký tự viết sát nhau gồm
toàn các chữ cái T (trắng), X (xanh), V(vàng) biểu diễn mầu ban đầu của 9 căn phòng theo
trật tự số hiệu của chúng.
Output
gồm một dòng
Nếu không có phương án thì in ra số 0
Trái lại thì in ra dãy thứ tự các robot được gọi (số hiệu các robot được viết sát nhau và in
ra kết quả có thứ tự từ điển bé nhất)
Example
Input:
159


123
357
147
5
369
456
789
258
XVXVXVTXT

Output:
2255799
Hướng dẫn:

Chú ý rằng, sau 3 lần quét vôi thì màu của một căn phòng trở lại như cũ. Bởi vậy, việc sử dụng
một robot ≥ 3 lần là không tối ưu. Ta có thể giải bài toán bằng cách sinh dãy tam phân độ dài 9,
mỗi giá trị a[i] chính là số lần gọi robot i.
2. DÃY ABC
Cho trước một số nguyên dương N (N 100), hãy tìm một xâu chỉ gồm các ký tự A, B, C thoả mãn
3 điều kiện:
- Có độ dài N
- Hai đoạn con bất kỳ liền nhau đều khác nhau (đoạn con là một dãy ký tự liên tiếp của xâu)
- Có ít ký tự C nhất.

Hướng dẫn:
Nếu dãy X
1
X
2
…X

n
thoả mãn 2 đoạn con bất kỳ liền nhau đều khác nhau, thì trong 4 ký tự liên tiếp
bất kỳ bao giờ cũng phải có 1 ký tự "C". Như vậy với một dãy con gồm k ký tự liên tiếp của dãy X
thì số ký tự C trong dãy con đó bắt buộc phải k div 4.
Tại bước thử chọn X
i
, nếu ta đã có T
i
ký tự "C" trong đoạn đã chọn từ X
1
đến X
i
, thì cho dù các
bước đệ quy tiếp sau làm tốt như thế nào chăng nữa, số ký tự "C" sẽ phải chọn thêm bao giờ cũng
(n - i) div 4. Tức là nếu theo phương án chọn X
i
như thế này thì số ký tự "C" trong dãy kết quả
(khi chọn đến X
n
) cho dù có làm tốt đến đâu cũng T
i
+ (n - i) div 4. Ta dùng con số này để
đánh giá nhánh cận, nếu nó nhiều hơn số ký tự "C" trong “Cấu hình tối ưu” thì chắc chắn có làm
tiếp cũng chỉ được một cấu hình tồi tệ hơn, ta bỏ qua ngay cách chọn này và thử phương án khác.

Các bạn tham khảo Code:

program ABC_STRING;
const
InputFile = 'ABC.INP';

OutputFile = 'ABC.OUT';
max = 100;
var
N, MinC: Integer;
X, Best: array[1 max] of 'A' 'C';
T: array[0 max] of Integer;
f: Text;

function Same(i, l: Integer): Boolean;
var
j, k: Integer;
begin
j := i - l;
for k := 0 to l - 1 do
if X[i - k] <> X[j - k] then
begin
Same := False; Exit;
end;
Same := True;
end;

function Check(i: Integer): Boolean;
var
l: Integer;
begin
for l := 1 to i div 2 do
if Same(i, l) then
begin
Check := False; Exit;
end;

Check := True;
end;

procedure KeepResult;
begin
MinC := T[N];
Best := X;
end;

procedure Try(i: Integer);
var
j: 'A' 'C';
begin
for j := 'A' to 'C' do
begin
X[i] := j;
if Check(i) then
begin
if j = 'C' then T[i] := T[i - 1] + 1
else T[i] := T[i - 1];
if T[i] + (N - i) div 4 < MinC then
if i = N then KeepResult
else Try(i + 1);
end;
end;
end;

procedure PrintResult;
var
i: Integer;

begin
for i := 1 to N do Write(f, Best[i]);
WriteLn(f);
WriteLn(f, '"C" Letter Count : ', MinC);
end;

begin
Assign(f, InputFile); Reset(f);
ReadLn(f, N);
Close(f);
Assign(f, OutputFile); Rewrite(f);
T[0] := 0;
MinC := N;
Try(1);
PrintResult;
Close(f);
end.

3. BÀI TOÁN NGƯỜI DU LỊCH
Cho n thành phố đánh số từ 1 đến n và m tuyến đường giao thông hai chiều giữa chúng, mạng
lưới giao thông này được cho bởi bảng C cấp nxn, ở đây C
ij
= C
ji
= Chi phí đi đoạn đường trực tiếp
từ thành phố i đến thành phố j. Giả thiết rằng C
ii
= 0 với i, C
ij
= + nếu không có đường trực

tiếp từ thành phố i đến thành phố j.
Một người du lịch xuất phát từ thành phố 1, muốn đi thăm tất cả các thành phố còn lại mỗi thành
phố đúng 1 lần và cuối cùng quay lại thành phố 1. Hãy chỉ ra cho người đó hành trình với chi phí ít
nhất. Bài toán đó gọi là bài toán người du lịch hay bài toán hành trình của một thương gia
(Traveling Salesman)
1 2
34
1
2
1
3
4
2
Hướng dẫn:
Hành trình cần tìm có dạng (x
1
= 1, x
2
, …, x
n
, x
n+1
= 1) ở đây giữa x
i
và x
i+1
: hai thành phố liên
tiếp trong hành trình phải có đường đi trực tiếp (C
ij
+ ) và ngoại trừ thành phố 1, không thành

phố nào được lặp lại hai lần. Có nghĩa là dãy (x
1
, x
2
, …, x
n
) lập thành 1 hoán vị của (1, 2, …, n).
Duyệt quay lui: x
2
có thể chọn một trong các thành phố mà x
1
có đường đi tới (trực tiếp), với mỗi
cách thử chọn x
2
như vậy thì x
3
có thể chọn một trong các thành phố mà x
2
có đường đi tới (ngoài
x
1
). Tổng quát: x
i
có thể chọn 1 trong các thành phố chưa đi qua mà từ x
i-1
có đường đi trực
tiếp tới (1 i n).

Nhánh cận: Khởi tạo cấu hình BestConfig có chi phí = + . Với mỗi bước thử chọn x
i

xem chi phí
đường đi cho tới lúc đó có < Chi phí của cấu hình BestConfig?, nếu không nhỏ hơn thì thử giá trị
khác ngay bởi có đi tiếp cũng chỉ tốn thêm. Khi thử được một giá trị x
n
ta kiểm tra xem x
n

đường đi trực tiếp về 1 không ? Nếu có đánh giá chi phí đi từ thành phố 1 đến thành phố x
n
cộng
với chi phí từ x
n
đi trực tiếp về 1, nếu nhỏ hơn chi phí của đường đi BestConfig thì cập nhật lại
BestConfig bằng cách đi mới.
Sau thủ tục tìm kiếm quay lui mà chi phí của BestConfig vẫn bằng + thì có nghĩa là nó không tìm
thấy một hành trình nào thoả mãn điều kiện đề bài để cập nhật BestConfig, bài toán không có lời
giải, còn nếu chi phí của BestConfig < + thì in ra cấu hình BestConfig - đó là hành trình ít tốn
kém nhất tìm được

Input: file văn bản TOURISM.INP
Dòng 1: Chứa số thành phố n (1 n 20) và số tuyến đường m trong mạng lưới giao
thông
m dòng tiếp theo, mỗi dòng ghi số hiệu hai thành phố có đường đi trực tiếp và chi phí đi
trên quãng đường đó (chi phí này là số nguyên dương 100)
Output: file văn bản TOURISM.OUT, ghi hành trình tìm được.















TOURISM.INP
4 6
1 2 3
1 3 2
1 4 1
2 3 1
2 4 2
3 4 4
TOURISM.OUT
1->3->2->4->1
Cost: 6


Các bạn tham khảo Code:


program TravellingSalesman;
const
InputFile = 'TOURISM.INP';
OutputFile = 'TOURISM.OUT';
max = 20;

maxC = maxlongint div 2;
var
C: array[1 max, 1 max] of longint;
X, BestWay: array[1 max + 1] of longint;
T: array[1 max + 1] of longint;
Free: array[1 max] of Boolean;
m, n: longint;
MinSpending: longint;

procedure Enter;
var
i, j, k: longint;
f: Text;
begin
Assign(f, InputFile); Reset(f);
ReadLn(f, n, m);
for i := 1 to n do
for j := 1 to n do
if i = j then C[i, j] := 0 else C[i, j] := maxC;
for k := 1 to m do
begin
ReadLn(f, i, j, C[i, j]);
C[j, i] := C[i, j];
end;
Close(f);
end;

procedure Init;
begin
FillChar(Free, n, True);

Free[1] := False;
X[1] := 1;
T[1] := 0;
MinSpending := maxC;
end;
procedure Try(i: longint);
var
j: longint;
begin
for j := 2 to n do
if Free[j] then
begin
X[i] := j;
T[i] := T[i - 1] + C[x[i - 1], j];
if T[i] < MinSpending then
if i < n then
begin
Free[j] := False;
Try(i + 1);
Free[j] := True;
end
else
if T[n] + C[x[n], 1] < MinSpending then
begin
BestWay := X;
MinSpending := T[n] + C[x[n], 1];
end;
end;
end;


procedure PrintResult;
var
i: longint;
f: Text;
begin
Assign(f, OutputFile); Rewrite(f);
if MinSpending = maxC then WriteLn(f, 'NO SOLUTION')
else
for i := 1 to n do Write(f, BestWay[i], '->');
WriteLn(f, 1);
WriteLn(f, 'Cost: ', MinSpending);
Close(f);
end;

begin
Enter;
Init;
Try(2);
PrintResult;
end.
4. Tour du lịch của Sherry ( )
Trong kì nghỉ hè năm nay sherry được bố thưởng cho 1 tour du lịch quanh N đất nước tươi đẹp với
nhiều thắng cảnh nổi tiếng ( vì sherry rất ngoan ). Tất nhiên sherry sẽ đi bằng máy bay.
Giá vé máy bay từ đất nước i đến đất nước j là C
ij
( dĩ nhiên C
ij
có thể khác C
ji
). Tuy được bố

thưởng cho nhiều tiền để đi du lịch nhưng sherry cũng muốn tìm cho mình 1 hành trình với chi phí
rẻ nhất có thể để dành tiền mua quà về tặng mọi người ( Các chuyến bay của sherry đều được
đảm bảo an toàn tuyệt đối ).
Bạn hãy giúp sherry tìm 1 hành trình đi qua tất cả các nước, mỗi nước đúng 1 lần sao cho chi phí
là bé nhất nhé.
Input

Dòng 1: N (5 < N < 16)
Dòng thứ i trong N dòng tiếp theo: Gồm N số nguyên, số thứ j là C
ij
(0 < C
ij
< 10001)

Output

Gồm 1 dòng duy nhất ghi chi phí bé nhất tìm được

Example










5. Chấm điểm ( )

Có N vị giám khảo trong kỳ thi chọn đội tuyển tin học. Kỳ thi bao gồm K bài. Vị giám khảo thứ i đề
nghị số điểm của bài j là A
ij
.
Hội đồng giám khảo muốn xác định số điểm cho mỗi bài sao cho:
Tổng số điểm bằng S.
Điểm của mỗi bài không bé hơn điểm của bài trước đó.
Số điểm của mỗi bài bằng điểm đề nghị cho bài này của một vị giám khảo nào đó.
Dữ liệu
Dòng đầu tiên chứa ba số nguyên S (1 ≤ S ≤ 200), (1 ≤ K ≤ 20), (1 ≤ N ≤ 20).
Dòng thứ i trong số N dòng tiếp theo chứa K số nguyên, số thứ j cho biết giá trị A
ij
là số
điểm vị giám khảo thứ i đề nghị cho bài thứ j.
Kết qủa
Nếu tồn tại một cách cho điểm thỏa mãn yêu cầu:
o Dòng thứ nhất: in ra 'YES'.
o Dòng thứ hai: in ra K số nguyên là điểm của mỗi bài tìm được.
Nếu không tồn tại cách cho điểm, in ra 'NO'.
Input:
Output:
6
0 1 2 1 3 4
5 0 3 2 3 4
4 1 0 2 1 2
4 2 5 0 4 3
2 5 3 5 0 2
5 4 3 3 1 0

8


Ví dụ







Hướng dẫn:
Kết quả của bài toán (nếu có) sẽ có dạng X
1
X
2
…X
k
. Trong mỗi bước duyệt, ta sẽ thử chọn X
i
trong
tập A
ji
(1 <= j <= n). Sau khi chọn X
i
, ta có thể đánh giá được S
min
(tổng điểm bé nhất có thể đạt
được khi duyệt xong) bằng dữ kiện dãy X tăng dần.

S
min

(tổng điểm khi chọn xong) = P[i] + X[i] * (k-i) với P[i] là tổng điểm đã có
- S
min
<= S : duyệt tiếp bài toán vẫn có thể có nghiệm
- S
min
> S : vô nghiệm
Đó cũng chính là cận trong quá trình duyệt để chương trình có thể chạy trong thời gian cho phép!

6. Hoán vị chữ cái ( )
Cho một xâu S chỉ gồm các chữ cái in hoa, 1 <= độ dài <= 9.
Yêu cầu:
1: Có bao nhiêu cách hoán vị các chữ cái của xâu S
2: Liệt kê các hoán vị đó theo thứ tự từ điển
Input
Gồm 1 dòng duy nhất chứa xâu S
Output
Dòng 1: Ghi số lượng hoán vị tìm được (K)
K dòng tiếp theo, mỗi dòng ghi một xâu hoán vị của xâu S theo đúng thứ tự từ điển
Example
Input:
ABAB
Output:
6
AABB
ABAB
ABBA
BAAB
BABA
BBAA

Dữ liệu
Kết quả
100 3 2
30 20 40
50 30 50
YES
30 30 40
100 2 3
1 1
2 2
3 3
NO
Hướng dẫn:
Hai yêu cầu cần giải quyết của bài toán này chính là số lượng cấu hình thỏa mãn và liệt kê
các cấu hình đó. Nếu như duyệt 2 lần, lần thứ nhất để đếm số lượng và lần thứ 2 để liệt
kê các cấu hình thì chương trình sẽ chạy quá thời gian cho phép. Bởi thế, ta nên tìm cách
đếm số cấu hình mà không cần phải duyệt quay lui.
Công thức:
Result = N! div (Count[ch])
với N là độ dài của S và Count[ch] là số lần xuất hiện của ký tự "ch".

7. Quan hệ ( )
Xét một tập N đối tượng có thể so sánh được (2<=n<=10). Giữa 2 đối tượng a và b có thể tồn tại
1 trong 3 quan hệ phân loại:
a = b; a < b; a > b;
Như vậy, với 3 đối tượng (a, b, c) có thể tồn tại 13 quan hệ phân loại như sau:
a = b = c; a = b < c; c < a = b; a < b = c
b = c < a; a = c < b; b < a = c; a < b < c
a < c < b; b < a < c; b < c < a; c < a < b
c < b < a;

Cho số n, hãy xác định số lượng quan hệ phân loại khác nhau.
Input
Gồm nhiều số n. Mỗi số trên 1 dòng. Kết thúc file là -1.
Output
Với mỗi n, đưa ra số lượng quan hệ phân loại tìm được, mỗi số trên 1 dòng (không có dòng
trống).
Example
Input:

2
3
-1

Output:

3
13

Hướng dẫn:
Bài này là một bài toán đếm tổ hợp. Bạn nhận xét một quan hệ phân loại sẽ có dạng
( = = ) < ( = = ) < < ( = = )
tức là chia thành các nhóm bằng nhau
Giả sử có k nhóm và gọi số phần tử trong mỗi nhóm là a1, a2, , ak.
Điều kiện: a1 + a2 + + ak <= n
Thế thì số quan hệ phân loại loại này bằng: n! / (a1! * a2! * a3! * * ak!)
Tóm lại công thức cuối cùng bằng:
Sum ( n! / (a1! * a2! * * ak!) | a1 + a2 + + ak <= n)

8. Quan hệ có điều kiện ( )
Ngày nay khi nghiên cứu quan hệ giữa các phần tử các nhà khoa học không đơn giản chỉ nghiên

cứu các quan hệ bình thường mà để thêm phần phức tạp là thêm vào đó 1 vài bộ điều kiện. Một
trong những điều kiện đó là số quan hệ '='
Như ta đã biết giữa 2 phần tử a, b sẽ có 3 quan hệ:
a = b, a > b, a < b.
Các nhà khoa học đưa ra 1 bộ gồm n phần tử. Sau khi tìm ra số lượng các quan hệ của n phần tử
này họ muốn biết nếu như số quan hệ '=' trong tập n phần tử này đúng bằng k thì sẽ có bao
nhiêu quan hệ như thế?
Input
Gồm nhiều bộ số n, k. Mỗi bộ số trên 1 dòng. Kết thúc file là -1. ( 1 < n < 11 )
Output
Với mỗi bộ số (n, k) đưa ra số quan hệ có điều kiện tìm được
Example
Input:
3 0
3 1
3 2
3 3
-1

Output:
6
6
0
1

Giải thích:
Với bộ 3 phần tử (a, b, c).

n=3, k=0:


a < b < c; a < c < b; b < a < c;
b < c < a; c < a < b; c < b < a;

n=3, k=1:
a = b < c; c < a = b; a < b = c
b = c < a; a = c < b; b < a = c;

n=3, k=3:
a = b = c;
CÁC THAO TÁC XỬ LÝ BIT

Dưới đây là những kiến thức về việc sử dụng các phép toán logic từ đó giúp cho việc thiết kế các
biểu thức logic dùng rất nhiều trong các phép toán điều kiện được nhanh chóng, chính xác, hiệu
quả.

* Quy ước về vị trí của các bit:
Mỗi byte bao gồm 8 bit được mã số từ phải sang trái còn gọi là bit thấp đến bit cao. Bit nằm ở bên
phải được xem là thấp hơn bit nằm ở bên trái. Các bit được đánh số như sau: 7 6 5 4 3 2 1 0
Mỗi bit có thể nhận 1 trong 2 giá trị là 0 hoặc 1. Tại mỗi thời điểm thực hiện chương trình mỗi bit
đươc nhận giá trị xác định. Mọi số nguyên trong máy đều biểu diễn dưới dạng nhị phân, thí dụ số
19 được biểu diễn như sau:
Bit 7 6 5 4 3 2 1 0
Giá trị 0 0 0 1 0 0 1 1 (số 19)

* Các phép toán logic
Các phép toán sau đây thực hiện trên các giá trị nguyên và cho kết quả là các giá trị nguyên.

1. Phép đảo bit NOT: đổi giá trị của mọi bit từ 0 thành 1 và ngược lại.

2. Phép cộng logic trên các bit OR thực hiện trên từng cặp bit tương ứng của các toán hạng

theo bảng cộng sau:






Quy tắc:
Tổng hai bit bằng 0 khi và chỉ khi cả hai bit bằng 0 ngoài ra tổng nhận giá trị 1. Phép OR
còn được gọi là phép “hoặc”.

3. Phép nhân logic trên các bit AND: thực hiện trên từng cặp bit tương ứng của các toán hạng
theo bảng nhân sau:






Quy tắc:
Tích hai bit bằng 1 khi và chỉ khi cả hai bit bằng 1, ngoài ra tích nhận giá trị 0. Phép AND
còn được gọi là phép “và”.
A
B
A OR B
0
0
0
0
1

1
1
0
1
1
1
1
A
B
A AND B
0
0
0
0
1
0
1
0
0
1
1
1
4. Phép cộng loại trừ trên các bit (XOR) : thực hiện trên từng cặp bit tương ứng của các toán
hạng theo bảng sau







Quy tắc:
Tổng loại trừ của hai bit bằng 1 khi và chỉ khi hai bit đó chứa các giá trị khác nhau, ngoài
ra tổng loại trừ nhận giá trị 0.
Phép toán trên cũng còn được gọi là phép so sánh khác (khác nhau là đúng, bằng nhau là sai) hay
còn gọi là phép “triệt tiêu”.


x SHR i : Phép dịch phải, cho giá trị có được từ số nguyên x sau khi dịch sang phải i bit.
x SHL i : Phép dịch trái, cho giá trị có được từ số nguyên x sau khi dịch sang trái i bit.

Với x = 2 ta có:
Trên đây là một số phép toán làm việc trên các bit mà ta hay dùng, trên cơ sở đó, ta xây dựng
được một số hàm, thủ tục hay dùng sau.

1. Hàm lấy giá trị bit: Hàm trả về giá trị 0 hoặc 1
Function GetBit(x, i:longint):longint;
Begin
GetBit:=(x SHR i) and 1;
End;

2. Thủ tục bật bit: Thủ tục gán trị 1 cho bit thứ i trong số nguyên x.
Procedure OnBit(Var x:longint; i:longint);
Begin
x:=x OR (1 SHL i);
End;

3. Thủ tục tắt bit: Thủ tục gán trị 1 cho bit thứ i trong số nguyên x.
Procedure OffBit(Var x:longint; i:longint);
Begin
x:=x AND (NOT(1 SHL i));

End;


Chúng ta xét qua các bài toán sau để tìm hiểu về ứng dụng của xử lý bit.
A
B
A XOR B
0
0
0
0
1
1
1
0
1
1
1
0
1. Số đặc biệt:
Xét một dãy gồm N số nguyên A
1
, A
2
, A
3
, A
n
. Trong dãy số trên có 1 số chỉ xuất hiện đúng một
lần, và các số còn lại xuất hiện một số chẵn lần.

Yêu cầu: Hãy tìm số đặc biệt của một dãy cho trước.
Dữ liệu: Trong file văn bản SDB gồm:
- Dòng đầu là số N (N ≤ 10
7
)
- N dòng tiếp, dòng thứ i là A
i
với |A
i
| ≤ 10
9
.
Kết quả: Một dòng duy nhất là số cần tìm.
Ví dụ:






Hướng dẫn: Lần lượt thực hiện phép XOR số thứ 1 với số thứ 2, lấy kết quả thực hiện với số thứ
3 và cứ thế cho hết N số. Vì phép XOR là phép “triệt tiêu”, do đó kết quả cuối cùng là số chỉ xuất
hiện 1 lần (không bị triệt tiêu). Bằng cách biểu diễn các số dưới dạng nhị phân rồi thực hiện phép
XOR, các bạn có thể dễ dàng chứng minh được thuật toán trên là đúng đắn.

res := 0;
For i := 1 to N do
begin
read(fi, a);
res := res xor a;

end;
writeln(fo, res);

2. Xâu cô lập:
Cho trước N (N ≤ 10000) xâu ký tự độ dài không quá 255 ký tự. Xâu cô lập được định nghĩa là xâu
chỉ xuất hiện duy nhất 1 lần trong N xâu đã cho, các xâu còn lại luôn xuất hiện một số chẵn lần.

Yêu cầu: Tìm xâu cô lập từ N xâu đã cho.
Dữ liệu: Trong file văn bản SINGLE.INP gồm
N dòng biểu diễn N xâu đã cho ban đầu.
Kết quả: Một dòng duy nhất là xâu cô lập.
Ví dụ:


Hướng dẫn: Cách làm tương tự với bài “Số đặc biệt”, ta thực hiện phép XOR với các mã ASCII.
SDB.INP
SDB.OUT
5
2
1
2
3
3
1
SINGLE.INP
SINGLE.OUT
- Hello, sir .
- Go away!
- Can I help you?
- Hello, sir.

- Can I help you?
- Go away!
3. Liệt kê tập con:
Cho tập hợp gồm N phần tử ( 1 ≤ N ≤ 20 ) Hãy liệt kê tất cả các tập con (kể cả rỗng) của tập hợp
đã cho.

Hướng dẫn: Xem như N phần tử là dãy N bit. Ta có thể biểu diễn tất cả các tập con bằng dãy N
bit, giá trị 1 (hoặc 0) biểu diễn sự tồn tại (hoặc không tồn tại) của mỗi phần tử. Giá trị dãy bit
tương ứng từ 0 2
n
- 1. Để kiểm tra sự tồn tại của 1 phần tử trong dãy bit có giá trị x, ta sử dụng
hàm GetBit như đã nêu trên. Đây là 1 bài toán rất cơ bản, các bạn có thể tự code.































DUYỆT BẰNG CÁCH CHIA ĐÔI TẬP HỢP
1. Tổng vector ( )
Trong mặt phẳng tọa độ có N véc tơ. Mỗi một véc tơ được cho bởi hai chỉ số x và y. Tổng của hai
véc tơ (x
i
, y
i
) và (x
j
, y
j
) được định nghĩa là một véc tơ (x
i
+ x
j
, y
i
+ y

j
). Bài toán đặt ra là cần chọn
một số véc tơ trong N véc tơ đã cho sao cho tổng của các vec tơ đó là véc tơ (U, V).
Yêu cầu: Đếm số cách chọn thoả mãn yêu cầu bài toán đặt ra ở trên.
Input
Dòng thứ nhất ghi số N (0 ≤ N ≤ 30).
N dòng tiếp theo, dòng thứ i ghi các số nguyên x
i
, y
i
lần lượt là hai chỉ số của véc tơ thứ i.
(|x
i
|, |y
i
| ≤ 100).
Dòng cuối cùng ghi số hai số nguyên U V (|U|, |V| ≤ 10
9
).
Output
Gồm một số duy nhất là số cách chọn thoả mãn.
Example
Input:
4
0 0
-1 2
2 5
3 3
2 5


Output:
4

Hướng dẫn: Nếu duyệt tổ hợp của N vector thì độ phức tạp của thuật toán là 2^N và chương
trình sẽ không cho kết quả trong thời gian cho phép với cỡ N ≤ 32. Cách giải quyết như sau:
- Chia tập N vector thành 2 tập bằng nhau A và B.
- Gọi F[x, y] là số cách chọn để có vector tổng (x, y) trên tập A. Để tính F[x, y] thì ta sẽ duyệt tất
cả các tập con của tập A, sau khi tính được vector tổng của mỗi tập con ta chỉ việc inc(F[x, y]).
- Tương tự ta sẽ duyệt trên tập B, sau khi tính được vector tổng (x1, y1) của mỗi tập con ta sẽ
inc(Res, F[U - x1, V - y1]) với Res là kết quả của bài toán.
Việc duyệt tập con của tập A, B có thể cài đặt như bài toán ở phần trước đã nhắc tới!

2. 34 đồng xu ( )
Bạn có 34 đồng xu có giá trị như sau:
xu [1] có giá trị 2
xu [2] có giá trị 3
xu [3] có giá trị 5

for n := 4 to 34 do
xu [n] có giá trị (xu[n-1] + xu[n-2] + xu[n-3])
Bạn hãy dùng nhiều đồng xu nhất để mua một món hàng có giá là X
Dữ liệu
Dòng đầu tiên là số test (không quá 1000). Mỗi dòng tiếp theo chứa một số nguyên X (1 ≤ X ≤
2000000000).
Kết quả
Với mỗi test, in ra "Case #" + số hiệu test + ": " + số lượng lớn nhất đồng xu cần dùng. Nếu
không có cách nào để đạt giá trị X thì in ra -1.
Ví dụ
Dữ liệu
4

1
5
8
9

Kết quả
Case #1: -1
Case #2: 2
Case #3: 2
Case #4: -1

Hướng dẫn: Gọi T[i] là số đồng xu nhiều nhất có thể mua món hang có giá trị là i. Trong mỗi
bước duyệt ở tập thứ 2, ta tiến hành cập nhật T[i]: T[i] := Max(T[i], F[i - x] + y) với x là
khối lượng tập hợp con, y là số lượng xu của tập. Mảng F có ý nghĩa tương tự T và đã được tính
trước ở bước 1.

3. Nhà hàng Trung Quốc ( )
Hàng năm vì muốn có không khí ấm cúng và cũng để tiết kiệm nên bạn thường tổ chức sinh nhật
ở nhà. Tuy nhiên trước sinh nhật năm nay vài hôm bạn đã thi đậu vào đội tuyển tin học quốc gia.
Đây là một sự kiện đặc biệt có ý nghĩa nên bạn quyết định mừng ngày sinh nhật của mình tại một
nhà hàng Trung Quốc sang trọng và bạn tự nhủ lần này nhất định phải tiêu xài rộng tay hơn. Mọi
việc chuẩn bị đã gần xong nhưng còn một vấn đề làm bạn khá nhức đầu, đó là làm sao chọn được
những món ăn mà mọi người cùng thích.
Nhà hàng có M món ăn khác nhau và thú vị ở chỗ là mỗi món ăn rất nhiều nên có thể đủ cho bao
nhiêu người cũng được, vì thế vấn đề là gọi món nào chứ không phải mỗi món gọi bao nhiêu. Có
tất cả N người đến dự tiệc sinh nhật (bao gồm cả bạn trong đó). Bạn đã tìm hiểu được danh sách
những món ăn yêu thích của từng người và bạn muốn rằng đối với mỗi người phải có ít nhất 2
món mà họ thích. Tuy nhiên sau khi ăn xong còn nhiều tiết mục hấp dẫn khác nên bạn cũng muốn
rằng bất kỳ ai cũng không có quá 2 món ăn yêu thích trong danh sách được đặt trước. Và vấn đề
cuối cùng, đây là tiền của bố mẹ nên cũng không nên tiêu xài quá đáng.

Yêu cầu
Hãy cho biết số tiền ít nhất phải trả để gọi một thực đơn thỏa mãn các yêu cầu trên.
Dữ liệu
- Dòng đầu tiên chứa hai số M, N
- Dòng thứ hai chứa M số P
i
là giá của món thứ i.
- Trong N dòng cuối cùng, dòng thứ k ghi danh sách các món yêu thích của người thứ k.
Kết quả
- Gồm một số duy nhất là kết quả của bài toán, hoặc
- in ra -1 nếu không có cách gọi món nào thỏa mãn.
Ví dụ
Dữ liệu:
5 3
100 150 300 425 200
1 2 4
1 3 4 5
1 4 5

Kết quả:
450

Giới hạn
- M ≤ 30.
- N ≤ 10.

Hướng dẫn: Theo đề ra thì mỗi người thích đúng 2 món trong thực đơn được chọn. Duyệt với m
div 2 món, với mỗi tổ hợp ta có dãy A
1
, A

2
, A
3
, , A
n
là số các món yêu thích của N người. Tương
tự với lần thứ 2 là B
1
, B
2
, B
3
, , B
n
. (Với A
i
, B
i
<= 2 và A
i
+ B
i
= 2). Chúng ta tìm cách mã hóa dãy
A, B thành số tự nhiên để tiện cho việc lưu trữ và tính toán.

4. Phân tập ( )
Cho N người(2≤N≤32) ,mỗi người có một số a
i
(1 ≤ a
i

≤ 10
9
) được gọi là độ tin cậy
Cần phân chia n người này vào 2 tập sao cho:
- Mỗi người thuộc đúng một tập
- Chênh lệch tổng độ tin cậy của 2 phần là bé nhất
Input
Dòng đầu chứa số nguyên N
Dòng tiếp theo chứa N số : số thứ i là độ tin cậy của người thứ i
Output

Ghi ra hai số u và v với u là độ chênh lệch nhỏ nhất và v là số cách phân chia

Example
Input:
5
1 5 6 7 8
Output:
1 3

Chú thích : Độ chênh lệch ít nhất của 2 phần là 1
Có 3 cách phân chia .3 cách phân chia nhóm 1 là (3,5) ,(1,3,4) và (1,2,5)

Hướng dẫn: Tư tưởng của bài toán vẫn là chia đôi để duyệt. Ta sẽ chọn một số người ở lần
duyệt thứ nhất và một số người ở lần duyệt thứ hai để cho vào “nhóm 1”.
Giả sử tổng độ tin cậy lần duyệt thứ nhất là x, thứ hai là y, gọi S là tổng độ tin cậy của N người.
Tổng độ tin cậy của “nhóm 1” trong TH này là x + y, và của “nhóm 2” là S - (x + y). Độ chênh
lệch tạo thành là Abs(S - (x + y) - (x + y)) = Abs(S - 2*(x+y)). Cách giải quyết cụ thể như sau :

- Duyệt N div 2 người, các tổng độ tin cậy thu được lưu vào một mảng C có tối đa là 2

16
phần tử.
Để tiện cho tính toán sau này, ta sẽ tối ưu mảng bằng cách loại bỏ những tổng bằng nhau và chỉ
giữ lại một, đồng thời dùng thêm 1 mảng để đếm số lần xuất hiện của tổng đó (cần sắp xếp lại
mảng C trước khi tối ưu nó). Ví dụ D[i] là số lần xuất hiện của tổng độ tin cậy C[i].

- Duyệt phần còn lại, mỗi tổng độ tin cậy X sinh ra, ta sẽ tìm C[i] sao cho Abs(S - 2*(X+C[i])) nhỏ
nhất có thể. Sau đó cập nhật kết quả tối ưu. Tìm kiếm nhị phân giá trị C[i] sẽ là rất hợp lí bởi
mảng C đã được sắp xếp và kích thước của nó cũng khá lớn.





























TÌM KIẾM NHỊ PHÂN

Các bạn có thể tham khảo kỹ thuật tìm kiếm nhị phân ở các tài liệu khác. Trong tài liệu này, chúng
ta sẽ lướt qua một vài ví dụ thật cơ bản để các bạn có thể hiểu thêm về nó.

1. Tải trọng của tuyến đường
Một hệ thống giao thông liên thông gồm N thành phố với tên 1 N (N <= 100). Có một số đoạn
đường hai chiều giữa một số cặp thành phố và mỗi đoạn đường có một tải trọng tối đa mà chỉ có
các xe với tải trọng không lớn hơn mới đi qua được.
Cần đi từ thành phố U tới V. Hãy tìm một hành trình sao cho tải trọng tối đa cho phép trên hành
trình đó là lớn nhất có thể được.

Dữ liệu : Trong file văn bản TAITRONG.INP gồm
Dòng đầu là 3 số N, U, V
Tiếp theo là một số dòng, mỗi dòng ghi ba số nguyên dương X Y Z với ý nghĩa có đường đi
giữa X và Y với tải trọng tối đa cho phép là Z (0 < Z <= 10000).

Kết quả : Ra file văn bản TAITRONG.OUT gồm
Dòng thứ nhất ghi tải trọng H tối đa của xe có thế.
Trong các dòng tiếp, mỗi dòng ghi tên một thành phố trong hành trình từ U kết thúc tại V.

Ví dụ :







Hướng dẫn:
Đặt H
min
= Min(a[i, j]), H
max
= Max(a[i, j]). Với mỗi giá trị h ( H
min
≤ h ≤ H
max
) ta xây dựng đồ thị
G(h) thỏa mãn: - N đỉnh tương ứng với N thành phố.
- 2 đỉnh i, j có cạnh nối nếu a[i, j] ≥ h.
Như vậy, nếu ta tìm thấy được một đường đi từ U tới V thì ta nói rằng : "Mạng giao thông có tải
trọng tối thiểu h". Bài toán trở thành "Tìm giá trị h lớn nhất để tồn tại đường đi từ U tới V".
Ta sẽ sử dụng kỹ thuật tìm kiếm nhị phân dựa theo nhận xét: Nếu mạng có tải trọng tối thiểu k,
và h là giá trị lớn nhất để "mạng giao thông có tải trọng tối thiểu h" thì k ≤ h ≤ H
max
. Ngược lại,
nếu không có lộ trình với tải trọng tối thiểu là k thì H
min
≤ h < k.
Với mỗi giá trị h, có thể duyệt DFS hoặc BFS để kiểm tra tồn tại đường đi từ U tới V hay không.
TAITRONG.INP
TAITRONG.OUT
4 1 4

1 2 10
2 4 1
1 3 5
3 4 3
3
1
3
4
2. Bộ sưu tập các đồng xu ( )
Cho N đồng xu có bán kính lần lượt là các số thực dương r
1
r
N
. Được đặt xung quanh một vòng
tròn sao cho:
Mỗi đồng xu tiếp xúc với 2 đồng xu
đặt cạnh nó và tiếp xúc với vòng tròn.
Biết được bán kính của từng đồng xu.
Yêu cầu: Tìm bán kính vòng tròn.
Input
Dòng đầu ghi số nguyên dương N
Dòng tiếp theo ghi N số r
i
( 1 ≤ i ≤ N )

Output
Gồm 1 dòng duy nhất ghi bán kính hình tròn ( độ chính xác đến 3 chữ số sau dấu phẩy )

Example


Input:
4
2 2 2 2

Output:
0.828

Giới hạn
1 ≤ N ≤ 10000
1 ≤ r
i
≤ 100000

Hướng dẫn:
Gọi O là tâm của đường tròn bán kính R, O
1
, O
2
, O
3
, O
n
là tâm của các đường tròn bán kính
tương ứng R
1
, R
2
, R
3
, R

n
.
Khi R thỏa mãn yêu cầu, ta có: O
1
OO
2
+ O
2
OO
3
+ O
3
OO
4
+ + O
n-1
OO
n
= 2pi (*)
Dễ dàng tính được các góc này theo độ dài 3 cạnh của các tam giác tương ứng. Để tìm R thỏa
mãn, ta sẽ chia nhị phân giá trị của R với R
min
= 0 và R
max
= tổng các R
i
. Giá trị R thỏa mãn (*)
chính là nghiệm của bài toán.
Chú ý xử lý dữ liệu tránh việc sai số khá lớn khi làm việc với số thực.
R

R
1

R2
R
3

R4
R5
R6
QUY HOẠCH ĐỘNG

Quy hoạch động là dạng bài toán khá phổ biến trong các kỳ thi HSG môn Tin học. Mục đích của
chúng là giải quyết các bài toán tối ưu. Vì không có một thuật toán tổng quát để giải tất cả các bài
toán quy hoạch động, do đó các ví dụ sau đây giúp các bạn làm quen và tiếp cận một số dạng
toán quy hoạch động.

1. Đi xem phim ( )
Nông dân John đang đưa các con bò của anh ta đi xem phim! Xe tải của anh ta thì có sức chứa có
hạn thôi, là C (100 <= C <= 5000) kg, anh ta muốn đưa 1 số con bò đi xem phim sao cho tổng
khối lượng của đống bò này là lớn nhất, đồng thời xe tải của anh ta vẫn chịu được.
Cho N (1 <= N <= 16) con bò và khối lượng W_i của từng con, hãy cho biết khối lượng bò lớn
nhất mà John có thể đưa đi xem phim là bao nhiêu.
Dữ liệu
Dòng 1: 2 số nguyên cách nhau bởi dấu cách: C và N
Dòng 2 N+1: Dòng i+1 chứa 1 số nguyên: W_i
Kết quả
Dòng 1: Một số nguyên là tổng khối lượng bò lớn nhất mà John có thể mang đi xem phim.
Ví dụ
Dữ liệu

259 5
81
58
42
33
61

Kết quả
242

Giải thích
81+58+42+61 = 242; đây là tổng khối lượng bò lớn nhất có thể được.

Hướng dẫn: Sử dụng mảng F : boolean với ý nghĩa F[i] = true nếu có cách chọn các con bò để
có khối lượng là i và ngược lại.

F[0] := true;
For i := 1 to n do
For j := C downto w[i] do
F[j] := F[j] or (F[j - w[i]]);

For i := C downto 0 do
if F[i] then // cách chọn tối ưu nhất!
begin
writeln(fo, i);
exit;
end;

Hãy tự kiểm tra lại xem vòng for thứ 2 là “for downto” chứ không phải là “for to”.
2. Bậc thang ( )

Bờm chơi trò chơi điện tử Lucky Luke đến màn phải điều khiển Lucky leo lên một cầu thang gồm n
bậc.

Các bậc thang được đánh số từ 1 đến n từ dưới lên trên. Lucky có thể đi lên một bậc thang, hoặc
nhảy một bước lên hai bậc thang. Tuy nhiên một số bậc thang đã bị thủng do cũ kỹ và Lucky
không thể bước chân lên được. Biết ban đầu, Lucky đứng ở bậc thang số 1 (bậc thang số 1 không
bao giờ bị thủng).

Chơi đến đây, Bờm chợt nảy ra câu hỏi: có bao nhiêu cách để Lucky leo hết được cầu thang?
(nghĩa là leo đến bậc thang thứ n). Bờm muốn nhờ bạn trả lời câu hỏi này.

Dữ liệu
Dòng đầu tiên: gồm 2 số nguyên n và k, là số bậc của cầu thang và số bậc thang bị hỏng
(0 ≤ k < n ≤ 100000).
Dòng thứ hai: gồm k số nguyên cho biết chỉ số của các bậc thang bị hỏng theo thứ tự tăng
dần.
Kết quả
In ra phần dư của số cách Lucky leo hết cầu thang khi chia cho 14062008.
Ví dụ
Dữ liệu
4 2
2 3

Kết qủa
0

Dữ liệu
90000 1
49000


Kết qủa
4108266

Hướng dẫn: Gọi F[i] là số cách để tới được bậc thang thứ i. Ta dễ dàng tìm ra công thức QHĐ là
F[i] := F[i-1] + F[i-2]. Độ phức tạp O(n).

3. Xếp hàng mua vé ( )
Có N người sắp hàng mua vé dự buổi hoà nhạc. Ta đánh số họ từ 1 đến N theo thứ tự đứng trong
hàng. Mỗi người cần mua một vé, song người bán vé được phép bán cho mỗi người tối đa hai vé.
Vì thế, một số người có thể rời hàng và nhờ người đứng trước mình mua hộ vé. Biết t
i
là thời gian
cần thiết để người i mua xong vé cho mình. Nếu người i+1 rời khỏi hàng và nhờ người i mua hộ vé
thì thời gian để người thứ i mua được vé cho cả hai người là r
i
.
Yêu cầu: Xác định xem những người nào cần rời khỏi hàng và nhờ người đứng trước mua hộ vé để
tổng thời gian phục vụ bán vé là nhỏ nhất.
Dữ liệu
Dòng đầu tiên chứa số N (1 ≤ N ≤ 60000).
Dòng thứ 2 ghi N số nguyên dương t
1
, t
2
, , t
N
. (1 ≤ t
i
≤ 30000)
Dòng thứ ba ghi N-1 số nguyên dương r

1
, r
2
, , r
N-1
. (1 ≤ r
i
≤ 30000)
Kết qủa
In ra tổng thời gian phục vụ nhỏ nhất.
Ví dụ
Dữ liệu:
5
2 5 7 8 4
4 9 10 10

Kết qủa
18

Dữ liệu:
4
5 7 8 4
50 50 50

Kết qủa
24

Hướng dẫn: Gọi F[i] là thời gian ít nhất để i người đầu tiên mua vé xong.
Ta có công thức QHĐ F[i] := Max(F[i-1] + T[i], F[i-2] + R[i-1]).
Độ phức tạp O(n).


4. Nối mạng ( )
Các học sinh khi đến thực tập trong phòng máy tính thường hay chơi trò chơi điện tử trên mạng.
Để ngăn ngừa, người trực phòng máy đã ngắt tất cả các máy tính ra khỏi mạng và xếp chúng
thành một dãy trên một cái bàn dài và gắn chặt máy xuống mặt bàn rồi đánh số thứ tự các máy
từ 1 đến N theo chiều từ trái sang phải. Các học sinh tinh nghịch không chịu thua, họ đã quyết
định tìm cách nối các máy trên bàn bởi các đoạn dây nối sao cho mỗi máy được nối với ít nhất một
máy khác. Để tiến hành công việc này, họ đã đo khoảng cách giữa hai máy liên tiếp. Bạn hãy giúp
các học sinh này tìm cách nối mạng thoả mãn yêu cầu đặt ra sao cho tổng độ dài cáp nối phải sử
dụng là ít nhất.

Dữ liệu
Dòng đầu tiên chứa số lượng máy N (1 ≤ N ≤ 25000).
Dòng thứ i trong số N-1 dòng tiếp theo chứa các khoảng cách từ máy i đến máy i+1
(i=1,2, ,N-1). Giả thiết rằng khoảng cách từ máy 1 đến máy N không vượt quá 10
6
.
Kết quả
Ghi ra độ dài của cáp nối cần sử dụng.
Ví dụ
Dữ liệu:
6
2
2
3
2
2

Kết qủa
7


Hướng dẫn: Gọi F[i] là độ dài của cách nối mạng ngắn nhất xét từ máy 1 i.
Ta có F[i] := Min(F[i-2], F[i-1]) + L[i-1];
Thời gian O(n)

5. Mua vé tàu hỏa ( )
Tuyến đường sắt từ thành phố A đến thành phố B đi qua một số nhà ga. Tuyến đường có thể biểu
diễn bởi một đoạn thẳng, các nhà ga là các điểm trên đó. Tuyến đường bắt đầu từ A và kết thúc ở
B, vì thế các nhà ga sẽ được đánh số bắt đầu từ A (có số hiệu là 1) và B là nhà ga cuối cùng.

Giá vé đi lại giữa hai nhà ga chỉ phụ thuộc vào khoảng cách giữa chúng. Cách tính giá vé như sau:
Khoảng cách giữa hai nhà ga (X)
Khoảng cách 0 < X <= L1 -> Giá vé C1
Khoảng cách 0 < X <= L2 -> Giá vé C2
Khoảng cách 0 < X <= L3 -> Giá vé C3
Nghĩa là với các giá vé C1, C2, C3 tương ứng bạn sẽ đi quảng đường tối đa là L1, L2, L3.

Vé để đi thẳng từ nhà ga này đến nhà ga khác chỉ có thể đặt mua nếu khoảng cách giữa chúng
không vượt quá L3. Vì thế nhiều khi để đi từ nhà ga này đến nhà ga khác ta phải đặt mua một số
vé. Hơn thế nữa, nhân viên đường sắt yêu cầu hành khách chỉ được giữ đúng một vé khi đi trên
tàu và vé đó sẽ bị huỷ khi hành khách xuống tàu.
Yêu cầu: Tìm cách đặt mua vé để đi lại giữa hai nhà ga cho trước với chi phí mua vé là nhỏ nhất
Input
Dòng đầu tiên ghi các số nguyên L1, L2, L3, C1, C2, C3 (1 <= L1 <= L2 <= L3 <= 10
9
; 1 <= C1
<= C2 <= C3 <= 10
9
) theo đúng thứ tự liệt kê ở trên.
Dòng thứ hai chứa số lượng nhà ga N ( 2 <= N <= 100000 )

Dòng thứ ba ghi hai số nguyên s, f là các chỉ số của hai nhà ga cần tìm cách đặt mua vé với chi
phí nhỏ nhất để đi lại giữa chúng.
Dòng thứ i trong số N - 1 dòng tiếp theo ghi số nguyên là khoảng cách từ nhà ga A (ga 1) đến nhà
ga thứ i + 1.
Output
Gồm 1 dòng duy nhất ghi chi phí nhỏ nhất tìm được
Example
Input:
3 6 8 20 30 40
7
2 6
3
7
8
13
15
23

Output:
70

Hướng dẫn: Gọi F[i] là chi phí ít nhất để đi đến ga i trên chặng từ s đến f.
Ta có F[i] := Min( F[i], F[j] + Chi phí từ j -> i )
Chú ý: Cài đặt khéo léo tránh TLE (Time Limit Exceeded)

6. Dạo chơi bằng xe buýt ( )
Một tuyến đường ở thành phố có các bến xe bus ở từng km tuyến đường. Mỗi lần qua bến, xe đều
đỗ để đón khách. Mỗi bến đều có điểm xuất phát. Một xe chỉ chạy không quá B km kể từ điểm
xuất phát của nó. Hành khách khi đi xe sẽ phải trả tiền cho độ dài đoạn đường mà họ ngồi trên
xe. Cước phí cần trả để đi đoạn đường độ dài i là Ci(i=1,2 B). Một du khách xuất phát từ 1 bến

nào đó muốn đi dạo L km theo tuyến nói trên. Hỏi ông ta phải lên xuống xe như thế nào để tổng
số tiền phải trả là nhỏ nhất có thể.

Dữ liệu vào:

Dòng đầu ghi 2 số nguyên dương B, L.
Dòng thứ i trong số B dòng tiếp theo ghi 1 số nguyên dương Ci ( 1 ≤ i ≤ B ).

Kết qủa

Một dòng duy nhất là số tiền nhỏ nhất phải trả

Giới hạn

0 ≤ B ≤ 100
0 ≤ L ≤ 10000
0 ≤ Ci ≤ 100

Ví dụ

Dữ liệu:
5 7
3
4
6
9
22
Kết qủa
14

×