You are on page 1of 26

Bài 1.

Tổng số nguyên liên tiếp


Cho số nguyên dương N và N số nguyên dương a1, a2, …, aN.
Yêu cầu: Hãy chọn ra k số liên tiếp trong N số đã cho sao cho tổng của chúng chia hết cho N và k
nhỏ nhất.
Dữ liệu: Vào từ file văn bản BAI1.INP.
- Dòng đầu ghi số nguyên dương N.
- Các dòng tiếp theo ghi N số nguyên dương a1, a2, …, aN.
Kết quả: Ghi ra file văn bản BAI1.OUT gồm một dòng ghi hai số nguyên dương k và j trong đó k
là số số nguyên được chọn, j là chỉ số của số nguyên dương đầu tiên trong k số được chọn.
Hai số trên cùng một dòng trong file dữ liệu vào và ra cách nhau ít nhất một kí tự trắng.
Giới hạn kích thước: N và các ai ≤ 32767
Ví dụ:
BAI1.INP BAI1.OUT
35 5 11
8 6 9 6 5 10 2 2 1 7 9 1 8 8 9 7 8 9 7 6 5 5 7 6 4
5 6 10 7 1 10 5 7 2 6

PHƯƠNG PHÁP GIẢI


Bài 1. Tổng số nguyên liên tiếp
Phương pháp 1: Tính tổng trực tiếp
- Xét lần lượt tổng k số nguyên liên tiếp k=1, 2,..,N; xem tổng nào thoản mãn đầu tiên đưa ra
kết quả bài toán.
For l:=1 to n do {l là số số nguyên liên tiếp}
Begin
For i:=1 to n-l+1 do
Begin
Tong:=0;
For j:=i to i+l-1 do Tong:=Tong+a[j];
If Tong mod n =0 then
Begin
k:=l; h:=i;
Exit;
End;
End;
End;
Nhận xét: việc tính bằng lệnh For j:=i to i+l-1 do Tong:=Tong+a[j]
mất nhiều thời gian tính toán có thể thay bằng nghĩa
là tính tổng sau có thể sử dụng tổng trước, cải tiến lại chương trình như sau:
a[0]:=0; k:=0; h:=0;
For l:=1 to n do
Begin
Tong:=0;
For i:=1 to l-1 do Tong:=Tong+a[i];
For i:=1 to n-l+1 do
Begin
Tong:=Tong+a[i+l-1]-a[i-1];
If Tong mod n =0 then
Begin
k:=l; h:=i;
Exit;
End;
End;
End;
Ta có thể tiếp tục cải tiến lại như sau:
a[0]:=0; k:=0; h:=0; TongTG:=0;
For l:=1 to n do
Begin
TongTG:=TongTG+a[l-1];
Tong:=TongTG;
For i:=1 to n-l+1 do
Begin
Tong:=Tong+a[i+l-1]-a[i-1];
If Tong mod n =0 then
Begin
k:=l; h:=i;
Exit;
End;
End;
End;

- Độ phức tạp của thuật toán là .


Phương pháp 2:

- Nhận xét nếu với ( ) khi đó

.
Đặt nếu khi đó
Min:=MaxN; b[0]:=0;
For i:=1 to n do b[i]:=-1;
Tong:=0;
For i:=1 to n do
Begin
Tong:=(Tong+a[i]) mod n;
If (b[Tong]>=0) And (i-b[Tong]<Min) then
Begin
Min:=i-b[Tong];
j:=b[Tong]+1;
End;
b[Tong]:=i;
End;

- Độ phức tạp của thuật toán là hiệu quả hơn nhiều phương pháp 1.
Chú ý: Không ảnh hưởng đến kết quả bài toán nếu thay .
CHƯƠNG TRÌNH
Bài 1. Tổng số nguyên liên tiếp
Phương pháp 1:
Const
Fi='BAI1.INP';
Fo='BAI1.OUT';
MaxN=50000;
Var
a: Array[0..MaxN] Of Longint;
n, k, h: Longint;
Procedure ReadFile;
Var
f: Text;
i: Longint;
Begin
Assign(f, Fi); Reset(f);
Readln(f,n);
For i:=1 to n do
Begin
Read(f,a[i]);
a[i]:=a[i] mod n;
End;
Close(f);
End;
Procedure xuly;
Var
i, j, l, Tong, TongTG: Longint;
Begin
a[0]:=0; k:=0; h:=0; TongTG:=0;
For l:=1 to n do
Begin
TongTG:=TongTG+a[l-1];
Tong:=TongTG;
For i:=1 to n-l+1 do
Begin
Tong:=Tong+a[i+l-1]-a[i-1];
If Tong mod n =0 then
Begin
k:=l; h:=i;
Exit;
End;
End;
End;
End;
Procedure WriteFile;
Var
f: Text;
i: Integer;
Begin
Assign(f, Fo); ReWrite(f);
Writeln(f,k,' ',h);
Close(f);
End;

Begin
ReadFile;
xuly;
WriteFile;
End.
Phương pháp 2:
Const
Fi='BAI1.INP';
Fo='BAI1.OUT';
MaxN=500000;
Var
a, b: Array[0..MaxN] Of Longint;
n, Min, j: Longint;
Procedure ReadFile;
Var
f: Text;
i: Longint;
Begin
Assign(f, Fi); Reset(f);
Readln(f,n);
For i:=1 to n do
Begin
Read(f,a[i]);
a[i]:=a[i] mod n;
End;
Close(f);
End;
Procedure Solve;
Var
i, Tong: Longint;
Begin
Min:=MaxN; b[0]:=0;
For i:=1 to n do b[i]:=-1;
Tong:=0;
For i:=1 to n do
Begin
Tong:=(Tong+a[i]) mod n;
If (b[Tong]>=0) And (i-b[Tong]<Min) then
Begin
Min:=i-b[Tong];
j:=b[Tong]+1;
End;
b[Tong]:=i;
End;
End;
Procedure WriteFile;
Var
f: Text;
i: Integer;
Begin
Assign(f, Fo); ReWrite(f);
If Min=MaxN then
Writeln(f,0,' ',0)
Else
Writeln(f,Min,' ',j);
Close(f);
End;
Begin
ReadFile;
Solve;
WriteFile;
End.

Bài 1: Số đoạn con nhiều nhất


Cho một dãy số nguyên không âm a 1; a2;...; aN. Hãy chia dãy số trên thành các đoạn con liên
tiếp sao cho tổng giá trị của tất cả các phần tử của các đoạn con đều bằng nhau và số đoạn con là
nhiều nhất.
Dữ liệu vào: cho trong file văn bản có tên DOANCON.IN có dạng:
- Dòng đầu ghi số nguyên dương N là số các phần tử có trong dãy .
- Các dòng tiếp theo ghi lần lượt các phần tử thuộc dãy.
Kết quả: ghi vào file văn bản có tên DOANCON.OUT có cấu trúc:
- Dòng đầu ghi 2 số p, q là số đoạn con và tổng giá trị của mỗi đoạn con.
- p dòng tiếp theo mỗi dòng ghi hai số b, d là chỉ số của phần tử bắt đầu và kết thúc một
đoạn con trong dãy đã cho.
Hai số trên một dòng của file dữ liệu vào và ra cách nhau một ký tự trắng.
Ví dụ:
DOANCON.IN DOANCON.OUT
10 5 9
1 3 5 9 7 2 1 3
4 1 4 4 4
9 5 6
7 9
10 10
Bài 1: Số đoạn con nhiều nhất
- Nhận xét:

+ Tính tổng .
+ Giả sử dãy đã cho chia thành k đoạn con thoản mãn yêu cầu bài toán, khi đó Tong chia hết
cho k và .
- Phương pháp: Xét k từ n đến 1, kiểm tra k chia hết Tong không, nếu chia hết thử chia
thành các đoạn con có thỏa mãn yêu cầu bài toán không. Số k đầu tiên thỏa mãn chính là kết quả
của bài toán.
Tong:=0; PhuongAn:=1;
For i:=1 to n do Tong:=Tong + a[i];
For i:=n downto 1 do
If Tong mod i =0 then
Begin
k:=Tong div i;
t:=0;
For j:=1 to n do
Begin
If t=0 then t:=k;
If t<0 then Break;
t:=t-a[j];
End;
If t=0 then
Begin
PhuongAn:=i;
Break;
End;
End;
Cụ Thể
3.1. Chọn học sinh giỏi cấp tỉnh
Bài 1: Số đoạn con nhiều nhất
Const
Fi='DOANCON.IN0';
Fo='DOANCON.OUT';
MaxN=50000;
Var
a: Array[1..MaxN] Of Longint;
Tong, n, PhuongAn: Longint;

Procedure ReadFile;
Var
f: Text;
i: Longint;
Begin
Assign(f, Fi); Reset(f);
Readln(f,n);
For i:=1 to n do Read(f,a[i]);
Close(f);
End;

Procedure Solve;
Var
i, j, t, k: Longint;
Begin
Tong:=0; PhuongAn:=1;
For i:=1 to n do Tong:=Tong + a[i];
For i:=n downto 1 do
If Tong mod i =0 then
Begin
k:=Tong div i;
t:=0;
For j:=1 to n do
Begin
If t=0 then t:=k;
If t<0 then Break;
t:=t-a[j];
End;
If t=0 then
Begin
PhuongAn:=i;
Break;
End;
End;
End;
Procedure WriteFile;
Var
f: Text;
k, t, i, u, v: Longint;
Begin
k:= Tong div PhuongAn;
Assign(f, Fo); Rewrite(f);
Writeln(f, PhuongAn,' ',k);
t:=k; u:=1;
For i:=1 to n do
Begin
t:=t-a[i];
If t=0 then
Begin
t:=k;
Writeln(f,u,' ',i);
u:=i+1;
End;
End;
Close(f);
End;

Begin
ReadFile;
Solve;
WriteFile;
End.
Biến đổi
4.1. Chọn học sinh giỏi cấp tỉnh
Bài 1. BIẾN ĐỔI
Từ một số nguyên Y có thể biến đổi thành số nguyên X nhờ hai phép biến đổi sau:
- Phép biến đổi 1: Y=Y - X nếu Y>X;
- Phép biến đổi 2: Y=Y + 1 nếu Y<X.
Yêu cầu: Cho hai số nguyên X và Y. Có thể biến đổi Y thành X được hay không? Trong trường hợp
có thể, tìm tổng số phép biến đổi?
Dữ liệu: Vào từ file văn bản BIENDOI.INP gồm một dòng chứa 2 số nguyên X và Y.
Kết quả: Đưa ra file văn bản BIENDOI.OUT gồm một dòng ghi tổng số phép biến đổi tìm được
trong trường hợp có thể; số 0 nếu ban đầu X=Y; số -1 nếu không biến đổi được.
Ví dụ:
BIENDOI.INP BIENDOI.OUT
10 97 12
Hướng dẫn
Bài 1. BIẾN ĐỔI
Ta xét các trường hợp như sau:
- Nếu X>0:
+ Nếu Y>X ta thực hiện phép biến đổi 1: số phép biến đổi là Y Div X;
+ Nếu Y<X ta thực hiện phép biến đổi 2: số phép biết đổi là X–Y.
- Nếu X=0:
+ Nếu Y>0 ta thực hiện phép biến đổi 1: vô hạn lần (không thể biến đổi Y thành X);
+ Nếu Y=0 ta được kết quả bài toán;
+ Nếu Y<0 thì Y<X ta thực hiện phép biến đổi 2: số phép biết đổi là X–Y.
- Nếu X<0:
+ Nếu Y>0 ta thực hiện phép biến đổi 1: vô hạn lần (không thể biến đổi Y thành X);
+ Nếu Y=0 ta thực hiện phép biến đổi 1: vô hạn lần (không thể biến đổi Y thành X);
+ Nếu Y<0:
Nếu Y>X ta thực hiện phép biến đổi 1: vô hạn lần (không thể biến đổi Y thành X);
Nếu X=Y ta được kết quả bài toán;
Nếu Y<X ta thực hiện phép biến đổi 2: số phép biết đổi là X–Y.
{KQ: kết quả bài toán}
If X>0 then
Begin
KQ:=0;
If Y>X then
Begin
KQ:=KQ + Y Div X;
Y:=Y Mod X;
End;
KQ:=KQ + X - Y;
End;
If X=0 then
Begin
If Y>0 then KQ:=-1;
If Y=0 then KQ:=0;
If Y<0 Then KQ:=X - Y;
End;
If X<0 then
Begin
If Y>0 then KQ:=-1;
If Y=0 then KQ:=-1;
If Y<0 then
Begin
If Y>X then KQ:=-1;
If Y=X then KQ:=0;
If Y<X then KQ:=X - Y;
End;
End;
If Y=X then KQ:=0;

Bài 1. BIẾN ĐỔI


Const
Fi='BienDoi.Inp';
Fo='BienDoi.Out';
Var
X, Y, KQ : Longint;
Procedure ReadFile;
Var
f: Text;
Begin
Assign(f,Fi); Reset(f);
Readln(f, X, Y);
Close(f);
End;
Procedure Solve;
Var
i, j: Longint;
Begin
If X>0 then
Begin
KQ:=0;
If Y>X then
Begin
KQ:=KQ + Y Div X;
Y:=Y Mod X;
End;
KQ:=KQ + X - Y;
End;
If X=0 then
Begin
If Y>0 then KQ:=-1;
If Y=0 then KQ:=0;
If Y<0 Then KQ:=X - Y;
End;
If X<0 then
Begin
If Y>0 then KQ:=-1;
If Y=0 then KQ:=-1;
If Y<0 then
Begin
If Y>X then KQ:=-1;
If Y=X then KQ:=0;
If Y<X then KQ:=X - Y;
End;
End;
If Y=X then KQ:=0;
End;

Procedure WriteResult;
Var
f: Text;
Begin
Assign(f,Fo); ReWrite(f);
Write(f,KQ);
Close(f);
End;

Begin
ReadFile;
Solve;
WriteResult;
End.
Phần tử lượng
Bài 1. Phân tử lượng
Const
Fi='H2O.INP';
Fo='H2O.OUT';
Var
a: Array['A'..'Z'] Of Longint;
PT: Set Of Char;
s: String;
KLPT: Longint;

Procedure Init;
Begin
Fillchar(a, Sizeof(a),0);
PT:=['H', 'O','N','C'];
End;

Procedure ReadFile;
Var
f: Text;
Begin
Assign(f, Fi); Reset(f);
Readln(f,s);
Close(f);
End;

Procedure Solve;
Var
i, Count, c: Integer;
Begin
i:=1;
While i<=Length(s) do
Begin
If s[i] In PT then
Begin
Count:=1;
If (i<Length(s)) And Not(s[i+1] In PT) then
Val(s[i+1], Count, c);
a[s[i]]:=a[s[i]]+Count;
End;
Inc(i);
End;
KLPT:=a['H']*1 + a['O']*16 + a['N']*14 + a['C']*12;
End;

Procedure WriteFile;
Var
f: Text;
Begin
Assign(f, Fo); Rewrite(f);
Writeln(f,KLPT);
Close(f);
End;

Begin
ReadFile;
Init;
Solve;
WriteFile;
End.
Tìm kiếm
5.1. Chọn học sinh giỏi cấp tỉnh
Bài 1: Ghép xâu
Một xâu ký tự S có thể được xây dựng từ một hoặc một số xâu ký tự A i cho trước bằng cách
ghép chúng với nhau. Mỗi xâu A i có độ dài không quá 10 ký tự, không chứa ký tự trắng và có thể
dùng nhiều lần trong việc xây dựng xâu S.
Ví dụ: Xâu S= “Kythichonhocsinhgioi” có thể được xây dựng từ 4 xâu A i là: A1=”Ky”;
A2=”thi”; A3=”chonhoc”; A4=”sinhgioi”.
Bài toán đặt ra: Cho xâu S và N xâu A i ; i = 1, 2, 3, …, N; N ≤ 100. Xâu S có thể được xây
dựng từ các xâu Ai hay không? Trường hợp có thể, hãy chỉ ra một cách xây dựng xâu S?
Dữ liệu vào: File văn bản có tên: BL1.INP bao gồm: dòng thứ nhất ghi xâu S; dòng thứ hai
ghi số N; N dòng tiếp theo mỗi dòng ghi xâu Ai.
Kết quả ghi ra file văn bản có tên BL1.OUT theo quy cách:
- Nếu xâu S không xây dựng được từ các xâu Ai đã cho thì ghi số 0;
- Nếu xâu S được xây dựng từ các xâu A i thì ghi chỉ số của các xâu A i tìm được trong một
cách xây dựng theo thứ tự. Hai số trên một dòng cách nhau một ký tự trắng.
Ví dụ:
BL1.INP BL1.OUT BL1.INP BL1.OUT
Kythihocsinhgioi 2153 Kythihocsinhgioi 0
5 4
thi Ky
Ky hocsinh
gioi gioi
ythi thichon
hocsinh
Bài 3: Tìm kiếm
Cho dãy số gồm N số nguyên. Tìm phần tử có giá trị tuyệt đối lớn thứ k trong dãy.
Dữ liệu vào: File văn bản BL3.INP có cấu trúc:
- Dòng đầu ghi 2 số nguyên dương N và k. ( 0 < k ≤ N ≤ 10000);
- Các dòng tiếp theo ghi N số nguyên. Hai số trên một dòng cách nhau một ký tự trắng.
Kết quả: File văn bản BL3.OUT ghi chỉ số của phần tử có giá trị tuyệt đối lớn thứ k trong
dãy. Nếu có nhiều phần tử như vậy thì chọn phần tử có chỉ số nhỏ nhất. Nếu không có phần tử nào
thoả mãn thì ghi số 0.
Ví dụ:
BL3.INP BL3.OUT BL3.INP BL3.OUT
9 2 7 64 0
17 -25 30 200 75 60 -81 81 8 -10 10 9 8 8
50
Bài 3: Tìm kiếm
Const
Fi='BL3.Inp';
Fo='BL3.Out';
MaxN=10000;
Var
a, b: Array[1..MaxN] Of Integer;
n, k, ak: Integer;

Procedure ReadFile;
Var
f: Text;
i: Integer;
Begin
Assign(f,Fi); Reset(f);
Readln(f,n,k);
For i:=1 to n do Read(f, a[i]);
Close(f);
End;

Procedure Quick_Sort(l, r: Integer);


Var
Key: Integer;
Tg: Integer;
i, j: Integer;
Begin
Key:=b[random(r-l+1) + l];
i:=l; j:=r;
Repeat
While b[i]>Key do Inc(i);
While b[j]<Key do Dec(j);
If i<=j then
Begin
Tg:=b[i]; b[i]:=b[j]; b[j]:=Tg;
Inc(i); Dec(j);
End;
Until i>j;
If l<j then Quick_Sort(l, j);
If i<r then Quick_Sort(i, r);
End;
Procedure Sort;
Var
i: Integer;
Begin
For i:=1 to n do b[i]:=abs(a[i]);
Quick_Sort(1,n);
End;

Procedure Solve;
Var
Key, Tg: Integer;
i, j: Integer;
Begin
Key:=-1;
j:=0; ak:=0; Tg:=-1;
For i:=1 to n do
Begin
If b[i]<>Key then
Begin
j:=j+1;
Key:=b[i];
End;
If j=k then
Begin
Tg:=b[i];
Break;
End;
End;
If Tg>0 then
For i:=1 to n do
If Abs(a[i])=Tg then
Begin
ak:=i;
Break;
End;
End;

Procedure WriteFile;
Var
f: text;
Begin
Assign(f, Fo); Rewrite(f);
Writeln(f,ak);
Close(f);
End;

Begin
ReadFile;
Sort;
Solve;
WriteFile;
End.

Bài 1. BIẾN ĐỔI


Ta xét các trường hợp như sau:
- Nếu X>0:
+ Nếu Y>X ta thực hiện phép biến đổi 1: số phép biến đổi là Y Div X;
+ Nếu Y<X ta thực hiện phép biến đổi 2: số phép biết đổi là X–Y.
- Nếu X=0:
+ Nếu Y>0 ta thực hiện phép biến đổi 1: vô hạn lần (không thể biến đổi Y thành X);
+ Nếu Y=0 ta được kết quả bài toán;
+ Nếu Y<0 thì Y<X ta thực hiện phép biến đổi 2: số phép biết đổi là X–Y.
- Nếu X<0:
+ Nếu Y>0 ta thực hiện phép biến đổi 1: vô hạn lần (không thể biến đổi Y thành X);
+ Nếu Y=0 ta thực hiện phép biến đổi 1: vô hạn lần (không thể biến đổi Y thành X);
+ Nếu Y<0:
Nếu Y>X ta thực hiện phép biến đổi 1: vô hạn lần (không thể biến đổi Y thành X);
Nếu X=Y ta được kết quả bài toán;
Nếu Y<X ta thực hiện phép biến đổi 2: số phép biết đổi là X–Y.
{KQ: kết quả bài toán}
If X>0 then
Begin
KQ:=0;
If Y>X then
Begin
KQ:=KQ + Y Div X;
Y:=Y Mod X;
End;
KQ:=KQ + X - Y;
End;
If X=0 then
Begin
If Y>0 then KQ:=-1;
If Y=0 then KQ:=0;
If Y<0 Then KQ:=X - Y;
End;
If X<0 then
Begin
If Y>0 then KQ:=-1;
If Y=0 then KQ:=-1;
If Y<0 then
Begin
If Y>X then KQ:=-1;
If Y=X then KQ:=0;
If Y<X then KQ:=X - Y;
End;
End;
If Y=X then KQ:=0;
Bài 2. SƯU TẬP
* Phương pháp 1: Đến lần lượt các số thỏa mãn yêu cầu bài toán đến số n thì dừng lại đưa ra kết
quả.
Tuy nhiên nếu n=1015 và với máy tính bình thường như hiện nay bạn phải đợi đến năm 3000
chưa chắc cho ra kết quả.
* Phương pháp 2: Quy hoạch động

- Tính mảng A[i] số các số có i chữ số với chữ số tận cùng khác 0: (cơ số
k).
- Tính mảng T[i] số các số thỏa mãn yêu cầu bài toán có n chữ số: T[i]=A[i-1]+A[i-3]+....
(A[i-1]: số các số có i chữ số với số các chữ số 0 tận cùng là 1, A[i-3]: số các số có i chữ số với số
các chữ số 0 tận cùng là 3, ...).
Nhận xét: ta có T[i]=k.T[i-1] nếu i lẻ và T[i]=k.T[i-1]+k-1 nếu i chẵn.
- Tính mảng L[i]=T[1]+T[2]+...+T[i] các khoảng của mảng T[i] từ đó đưa ra được số cần
tìm có bao nhiêu chữ số.
Từ các mảng phương án A[i], T[n], L[i] và nhận xét ta xác định số thứ n mà Minh yêu thích
ở hệ cơ số k.
{MaxM=100000000000000000; Max=100;}
Tg:=k-1; a[1]:=0; MaxN:=1;
{Tính mảng a}
Repeat
Inc(MaxN);
a[MaxN]:=Tg;
For i:=1 to MaxN-1 do a[MaxN]:=a[MaxN]-a[i];
Tg:=Tg*k;
Until Tg>MaxM;
{Tính mảng t}
For i:=1 to MaxN do
Begin
t[i]:=a[i];
j:=i-2;
While j>0 do
Begin
t[i]:=t[i]+a[j];
j:=j-2;
End;
End;
{Tính mảng l}
L[0]:=0;
For i:=1 to MaxN do l[i]:=l[i-1]+t[i];
{Lặp đếm phương án}
While n>0 do
Begin
m:=1;
While l[m]<n do Inc(m);
m:=m-1;
c:=l[m]; j:=0;
While n>c do
Begin
Inc(j);
n:=n-c;
If m mod 2 = 1 then n:=n-1;
End;
Tg:=j;
For i:=1 to m do Tg:=Tg*k;
KQ:=KQ+Tg;
End;
Bài 3: Tìm kiếm
Phương pháp giải:
- Sắp xếp theo thứ tự giảm dần theo giá trị tuyệt đối của các phần tử;
- Xác định phần tử lớn thứ k theo giá trị tuyệt đối trong dãy;
- Đưa ra kết quả.
Key:=-1;
j:=0; ak:=0; Tg:=-1;
For i:=1 to n do
Begin
If b[i]<>Key then
Begin
j:=j+1; Key:=b[i];
End;
If j=k then
Begin
Tg:=b[i]; Break;
End;
End;
If Tg>0 then
For i:=1 to n do
If Abs(a[i])=Tg then
Begin
ak:=i; Break;
End;

5.2. Chọn đội tuyển dự thi quốc gia


Bài 1. MÔN HỌC
- Tiến hành sắp xếp (QuickSort) theo thứ tự giảm dần tên các môn học rồi đưa ra kết quả bài
toán.
Count:=0; s:=''; i:=1; {Count là kết quả bài toán}
While i<=n do
Begin
If Not((Length(s)>=Length(a[i]))_
and (Copy(s,1,Length(a[i]))=a[i])) then
Begin
Inc(Count);
s:=a[i];
End;
Inc(i);
End;
Bài 2. ĐỒNG HỒ
- Tính toán những giờ nào 2 kim gặp nhau: bằng cách tính góc của kim đồng hồ: kim dài 1
phút tương ứng 60, kim ngắn 1 giờ tương ứng 300 từ đó đưa ra kết quả các góc khi 2 kim gặp nhau.
- Dựa vào mảng 2 kim gặp nhau đưa ra kết quả bài toán.
n:=48; Count:=0;
For k:=0 to n-1 do a[k]:=k*360/11;
t1:=30*Gio1+Phut1/2;
t2:=30*Gio2+Phut2/2;
If t1>t2 then t2:=t2+720;
For k:=0 to n-1 do
If (a[k]>=t1) And (a[k]<=t2) then Inc(Count);

5.2. Chọn đội tuyển dự thi quốc gia


Bài 1. MÔN HỌC
Chế độ học theo tín chỉ cho phép Minh đi nghe giảng và thi nhiều môn khác nhau. Hôm nay
Minh muốn tổng kết lại mình đã học qua bao nhiêu môn trong thời gian qua. Tên các môn học đã
được ghi lại đầy đủ trong một danh sách, mỗi tên trên một dòng. Nhưng việc thống kê các môn học
hóa ra cũng không hoàn toàn giản đơn vì 2 lý do. Thứ nhất là tên một môn học có thể xuất hiện
nhiều lần trong danh sách; thứ hai là do quá vội, tên môn học thường được viết tắt. Quy tắc viết tắt
khá đơn giản: Minh bỏ một số chữ cái cuối tên, ví dụ môn “algebra” (Đại số) có thể được ghi trong
danh sách là “algebr” hoặc “algeb” hay đơn giản là “alg”, nhưng không phải là “algra”. Hãy xác
định số môn khác nhau mà Minh đã học.
Dữ liệu: Vào từ file văn bản COURSES.INP:
 Dòng đầu chứa số nguyên n là số dòng trong danh sách ( ),
 Mỗi dòng trong n dòng tiếp theo chứa một xâu chỉ bao gồm các chữ cái latinh thường và
dấu gạch dưới (“_”), mỗi xâu có độ dài không quá 20.
Dữ liệu vào đảm bảo không có hai môn học nào có cùng xâu viết tắt.
Kết quả: Đưa ra file văn bản COURSES.OUT một số nguyên là số môn học khác nhau mà Minh đã
học.
Ví dụ:
COURSES.INP COURSES.OUT COURSES.INP COURSES.OUT
3 2 4 1
algebra algebr
algeb alg
history algebra
algeb

Câu 1: Số chính phương


Sau tiết học về ‘Số chính phương’, Minh rất thích thú và nghĩ ra một trò chơi để đố các bạn.
Minh sẽ nghĩ ra một số nguyên dương bất kì và đố các bạn xem số đó có là tổng của 4 số chính
phương hay không. Ví dụ: 53=22+22+32+62; 94=22+42+52+72.
Yêu cầu: Em hãy giúp các bạn của Minh tìm cách phân tích một số nguyên dương N thành tổng các
bình phương của 4 số nguyên dương.
Dữ liệu: Vào từ file văn bản CAU1.INP gồm một dòng chứa một số nguyên dương N (0 < N < 105).
Kết quả: Đưa ra file văn bản CAU1.OUT gồm một dòng ghi 4 số nguyên dương có tổng các bình
phương bằng N. Nếu có nhiều cách phân tích thì chỉ đưa ra một cách. Nếu không phân tích được thì
ghi ra số -1.
Ví dụ:
CAU1.INP CAU1.OUT CAU1.INP CAU1.OUT
53 2236 9 -1
6.1. Chọn học sinh giỏi cấp tỉnh
Câu 1: Số chính phương
Phương pháp giải: Sử dụng 3 vòng lặp để kiểm tra xem một số có là tổng của 4 số chính phương
hay không:
Giả sử có kết quả , giả sử khi đó ,
, :
For i1:=1 to Round(Sqrt(n/4)) do
For i2:=i1 to Round(Sqrt((n-i1*i1)/3)) do
For i3:=i2 to Round(Sqrt((n-i1*i1-i2*i2)/2)) do
Begin
t:=n-i1*i1-i2*i2-i3*i3;
i4:=Round(Sqrt(t));
If i4*i4=t then {kết quả}
End;
Có thể chạy tốt với kết quả n=100.000.000
Câu 1: Số chính phương
Const
Fi='Cau1.INP';
Fo='Cau1.OUT';
Var
n: Longint;

Procedure ReadFile;
Var
f: Text;
Begin
Assign(f, Fi); Reset(f);
Readln(f,n);
Close(f);
End;

Procedure Solve;
Var
f: Text;
i1, i2, i3, i4, t: Longint;
Begin
Assign(f, Fo); Rewrite(f);
For i1:=1 to Round(Sqrt(n/4)) do
For i2:=i1 to Round(Sqrt((n-i1*i1)/3)) do
For i3:=i2 to Round(Sqrt((n-i1*i1-i2*i2)/2)) do
Begin
t:=n-i1*i1-i2*i2-i3*i3;
i4:=Round(Sqrt(t));
If i4*i4=t then
Begin
Writeln(f,i1,' ',i2,' ',i3,' ',i4);
Close(f);
Halt;
End;
End;
Writeln(f,-1);
Close(f);
End;

Begin
ReadFile;
Solve;
End.

Câu 2: Số đối xứng


Một số nguyên dương được gọi là đối xứng nếu viết các chữ số của nó theo chiều ngược lại
ta nhận được số ban đầu. Có một cách để sinh ra số đối xứng từ một số nguyên dương N (không
phải là số đối xứng) như sau:
Bước 1: Tính tổng của số N với số được tạo thành bằng cách viết các chữ số của N theo
chiều ngược lại;
Bước 2: Nếu tổng nhận được ở Bước 1 chưa là số đối xứng thì quay lại thực hiện Bước 1 với
N là tổng vừa nhận được. Nếu tổng nhận được là số đối xứng thì việc sinh ra số đối xứng kết thúc.
Ví dụ: N = 14 thì số đối xứng nhận được là 55 vì 14 + 41 = 55;
N = 48 thì số đối xứng nhận được là 363 vì , .
Yêu cầu: Cho số nguyên dương N, tìm số đối xứng sinh ra từ N theo cách trên.
Dữ liệu: Vào từ file văn bản CAU2.INP một dòng duy nhất chứa số nguyên dương N (N<109).
Kết quả: File văn bản CAU2.OUT chứa số đối xứng tìm được.
Ví dụ:
CAU2.INP CAU2.OUT CAU2.INP CAU2.OUT
14 55 48 363
Câu 2: Số đối xứng
- Thực hiện tính toán theo yêu cầu bài toán.
- Kết quả thực hiện các phép lặp như bài toán yêu cầu dẫn đến số nguyên có hàng 1000 chữ
số do vậy ta không thể khai báo biến lặp thông thường (Longint hay Int64) ta sử dụng các tính toán
với số lớn.
- Ở đây sử dụng mảng (cơ số 10) để biểu diễn số và thực hiện phép cộng thông thường.
- Hàm kiểm tra tính đối xứng:
Function fDoiXung: Boolean;
Var
i: Integer;
Begin
fDoiXung:=False;
For i:=1 to na div 2 do
If a[i]<>a[na-i+1] then Exit;
fDoiXung:=True;
End;
- Thủ tục cộng:
+ Ví dụ 48+84 = (4+8)*10 + (8+4)=132, như vậy ở đây phép tính là đối xứng do đó ta chỉ
cần tính (4+8) và suy ra kết quả.

+
Procedure CongDao;
Var
i, m: Integer;
Tg: Longint;
Begin
m:=na div 2;
If m*2<>na then Inc(m);
For i:=1 to m do
Begin
a[i]:=a[i]+a[na-i+1];
a[na-i+1]:=a[i];
End;
Tg:=0;
For i:=1 to na do
Begin
Tg:=Tg+a[i];
a[i]:=Tg mod 10;
Tg:=Tg div 10;
End;
While Tg>0 do
Begin
Inc(na);
a[na]:=Tg mod 10;
Tg:=Tg div 10;
End;
End;
- Lặp tìm kết quả
Procedure Solve;
Begin
While fDoiXung=False do CongDao;
End;
Câu 2: Số đối xứng
Const
Fi='CAU2.INP';
Fo='CAU2.OUT';
MaxN=100000;
Var
n: Int64;
a: Array[1..MaxN] Of Longint;
na: Integer;

Procedure ReadFile;
Var
f: Text;
Begin
Assign(f, Fi); Reset(f);
Readln(f,n);
Close(f);
End;
Procedure Init;
Var
i, c: Integer;
s: String;
Begin
na:=0;
Str(n,s);
For i:=1 to Length(s) do
Begin
Inc(na);
Val(s[i],a[na],c);
End;
End;

Function fDoiXung: Boolean;


Var
i: Integer;
Begin
fDoiXung:=False;
For i:=1 to na div 2 do
If a[i]<>a[na-i+1] then Exit;
fDoiXung:=True;
End;

Procedure CongDao;
Var
i, m: Integer;
Tg: Longint;
Begin
m:=na div 2;
If m*2<>na then Inc(m);
For i:=1 to m do
Begin
a[i]:=a[i]+a[na-i+1];
a[na-i+1]:=a[i];
End;
Tg:=0;
For i:=1 to na do
Begin
Tg:=Tg+a[i];
a[i]:=Tg mod 10;
Tg:=Tg div 10;
End;
While Tg>0 do
Begin
Inc(na);
a[na]:=Tg mod 10;
Tg:=Tg div 10;
End;
End;
Procedure Solve;
Begin
While fDoiXung=False do CongDao;
End;

Procedure WriteFile;
Var
f: Text;
i: Integer;
Begin
Assign(f,Fo); Rewrite(f);
For i:=1 to na do Write(f,a[i]);
Close(f);
End;

Begin
ReadFile;
Init;
Solve;
WriteFile;
End.

Câu 1: Đếm ước


Khi học về các số tự nhiên, Minh phát hiện ra nhiều điều thú vị về các số đó, đặc biệt khi học
về ước số của một số tự nhiên. Minh rất thích thú với việc tìm ra được các ước số của một số tự
nhiên n cho trước. Minh rất muốn biết với số tự nhiên n thì nó có bao nhiêu ước số.
Yêu cầu: Hãy lập trình giúp Minh tìm số ước của số tự nhiên n;
Dữ liệu: Vào từ file văn bản CAU1.INP gồm 1 dòng chứa số tự nhiên n (1≤ n ≤ 109).
Kết quả: Đưa ra file văn bản CAU1.OUT gồm 1 dòng chứa số ước của số tự nhiên n.
Ví dụ:
CAU1.INP CAU1.OUT CAU1.INP CAU1.OUT
1 1 6 4
Câu 1: Đếm ước
* Bổ sung đề bài: tìm số các ước tự nhiên
Nhận xét: giả sử là ước của , khi đó có số sao cho có nghĩa là
cũng ước của . Do đó nếu là ước của thì cũng là ước của giả sử

(do ngược lại mâu thuẫn với ) gợi ý cho ta cách đếm ước như sau:
For i:=1 to Sqrt(n) do
If n mod i = 0 then
Begin
If i<>n div i then
Count:=Count+2
Else Count:=Count+1;
End;
Câu 1: Đếm ước
Const
Fi='CAU1.INP';
Fo='CAU1.OUT';
Var
n, Count: Int64;
Procedure ReadFile;
Var
f: Text;
Begin
Assign(f, Fi); Reset(f);
Readln(f,n);
Close(f);
End;

Procedure Solve;
Var
i, m: Longint;
Begin
Count:=0;
m:=Round(Sqrt(n));
For i:=1 to m do
If n mod i = 0 then
Begin
If i<>n div i then
Count:=Count+2
Else Count:=Count+1;
End;
End;

Procedure WriteFile;
Var
f: Text;
Begin
Assign(f, Fo); Rewrite(f);
Writeln(f,Count);
Close(f);
End;

Begin
ReadFile;
Solve;
WriteFile;
End.
Câu 2: Số nhỏ nhất
Cho dãy số nguyên dương: a1, a2, …, an (1 ≤ n ≤109; 1 ≤ ai < 106; i = 1, 2, 3, ..., n).
Yêu cầu: Tìm số nguyên dương nhỏ nhất không xuất hiện trong dãy số đã cho.
Dữ liệu: Vào từ file văn bản CAU2.INP
 Dòng 1 chứa số nguyên dương n (1 ≤ n ≤ 109);
 Dòng 2 chứa n số nguyên dương a1, a2,… , an (1≤ ai < 106). Các số cách nhau một dấu cách.
Kết quả: Đưa ra file văn bản CAU2.OUT gồm một dòng chứa số nguyên dương nhỏ nhất tìm được.
Ví dụ:
CAU2.INP CAU2.OUT CAU2.INP CAU2.OUT
3 1 8 5
263 1 30 4 65 2 37 27 3

Câu 2: Số nhỏ nhất


* Bổ sung đề bài: 1 ≤ n ≤ 107
- Sử dụng một mảng đánh dấu các số nguyên đã có trong dãy.
- Tiến hành đọc tệp và đánh đấu tất cả các số nguyên đã có trong dãy.
Assign(f, Fi); Reset(f);
Readln(f,n);
For i:=1 to n do
Begin
Read(f, ai);
a[ai]:=False;
End;
Close(f);
- Tìm số đầu tiên chưa đánh dấu và đưa ra kết quả.
Min:=MaxAi;
For i:=1 to MaxAi do
If a[i] then
Begin
Min:=i;
Break;
End;
Câu 2: Số nhỏ nhất
Const
Fi='CAU2.INP';
Fo='CAU2.OUT';
MaxAi=1000001;
Var
a: Array[0..MaxAi] Of Boolean;
Min: Longint;

Procedure Init;
Begin
Fillchar(a, Sizeof(a), True);
End;

Procedure ReadFile;
Var
f: Text;
n, i, ai: Longint;
Begin
Assign(f, Fi); Reset(f);
Readln(f,n);
For i:=1 to n do
Begin
Read(f, ai);
a[ai]:=False;
End;
Close(f);
End;

Procedure Solve;
Var
i: Longint;
Begin
Min:=MaxAi;
For i:=1 to MaxAi do
If a[i] then
Begin
Min:=i;
Break;
End;
End;

Procedure WriteFile;
Var
f: Text;
Begin
Assign(f, Fo); Rewrite(f);
Writeln(f,Min);
Close(f);
End;

Begin
Init;
ReadFile;
Solve;
WriteFile;
End.
Câu 4: Tìm số
Sau ngày thi thứ nhất, Minh rất vui vẻ vì mình làm bài rất tốt. Với động lực đó, Minh càng
hăng say học tập. Hôm nay, Minh bắt tay vào nghiên cứu số Fibonaci. Sử dụng công thức tổng quát
của dãy số Fibonaci:

Minh lần lượt tính các số của dãy số Fibonaci và viết chúng cạnh nhau từ trái qua phải tạo
thành một dãy số vô hạn: 112358132134... Minh có một câu hỏi: với dãy số vô hạn được tạo bằng
cách trên, thì chữ số thứ K tính từ trái qua phải là chữ số nào. Các bạn hãy lập trình giúp Minh trả
lời câu hỏi trên.
Yêu cầu: Cho số tự nhiên K, hãy tìm chữ số thứ K (tính từ trái qua phải) của dãy số vô hạn mà
Minh tạo ra.
Dữ liệu: Vào từ file văn bản CAU4.INP gồm một dòng chứa một số tự nhiên K (1 ≤ K ≤ 109).
Kết quả: Đưa ra file văn bản CAU4.OUT gồm một dòng ghi chữ số thứ K của dãy số vô hạn mà
Minh tạo ra.
Ví dụ:
CAU4.INP CAU4.OUT CAU4.INP CAU4.OUT
1 1 11 3

Câu 4: Tìm số
Const
Fi='CAU4.INP';
Fo='CAU4.OUT';
MaxN=10000;
CoSo=100000000000000000;
LCoSo=17;
Var
a: Array[1..2,0..MaxN] Of Int64;
k, i1, i2: Longint;
KQ: String;
Procedure Init;
Begin
Fillchar(a, Sizeof(a), 0);
i1:=2; i2:=1;
End;
Function Fn(n: Int64): Longint;
Var
s: String;
Begin
Str(n, s);
Fn:=Length(s);
End;

Procedure ReadFile;
Var
f: Text;
Begin
Assign(f, Fi); Reset(f);
Readln(f,k);
Close(f);
End;
Procedure Solve;
Var
i, n, j, la: Longint;
Tg: Int64;
s: String;
Begin
a[1,1]:=1; a[1,0]:=1;
a[2,1]:=1; a[2,0]:=1;
If k<=2 then
Begin
KQ:='1';
Exit;
End;
k:=k-2;
Repeat
i:=i1; i1:=i2; i2:=i;
n:=a[i2,0];
Tg:=0;
For j:=1 to n do
Begin
a[i1,j]:=Tg+a[i1,j]+a[i2,j];
Tg:=a[i1,j] div CoSo;
a[i1,j]:=a[i1,j] mod CoSo;
End;
While Tg>0 do
Begin
Inc(n);
a[i1,n]:=Tg mod CoSo;
Tg:=Tg div CoSo;
End;
a[i1,0]:=n;
la:=Fn(a[i1,n])+(n-1)*lCoSo;
If k<=la then
Begin
Str(a[i1,n],s);
If k<=Length(s) then
Begin
KQ:=s[k];
Exit;
End;
k:=k-Length(s);
For j:=n-1 downto 1 do
Begin
Str(a[i1,j],s);
For i:=Length(s)+1 to lCoSo do s:='0' + s;
If k<=lCoSo then
Begin
KQ:=s[k];
Exit;
End;
k:=k-lCoSo;
End;
End;
k:=k-la;
Until k<=0;
End;
Procedure WriteFile;
Var
f: Text;
Begin
Assign(f, Fo); Rewrite(f);
Writeln(f,KQ);
Close(f);
End;

Begin
Init;
ReadFile;
Solve;
WriteFile;
End.

You might also like