Tải bản đầy đủ (.docx) (19 trang)

bồi dưỡng học sinh giỏi tin học 10

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 (175.71 KB, 19 trang )

Chuyên đề bồi dưỡng giáo viên tin học THCS

Nội dung
I. Rèn luyện tư duy thuật toán cho học sinh THCS
1. Tại sao phải rèn luyện kỹ năng tìm tòi thuật toán
2. Xác định rõ INPUT và OUTPUT.
3. Mịn dần thuật toán.
II. Rèn luyện phong cách lập trình tốt cho học sinh THCS
1.Quy ước về cách đặt tên cho các định danh.
3. Phong cách viết mã nguồn
4.Tối ưu sự thực thi mã nguồn
5. Tạo các bộ thử
III. Các dạng toán bồi dưỡng môn tin cho HSG THCS
1.Các bài toán số học
2.Các bài toán về mảng một chiều , hai chiều.
3. Các bài toán về xử lý xâu

.

I. Rèn luyện tư duy thuật toán cho học sinh THCS.
1. Tại sao phải rèn luyện tư duy thuật toán cho học sinh THCS.
Trong quyển sách nổi tiếng của mình về NNLT Pascal ( viết năm 1970), tác giả
N.With đã viết một dòng ngay từ trang đầu:
CHƯƠNG TRÌNH= THUẬT TOÁN +CẤU TRÚC DỮ LIỆU
Như vậy thuật toán là phần quan trong bậc nhất để tạo nên một chương trình.
Nhưng hết tiểu học, học sinh vẫn chưa được làm quen với khái niệm thuật toán.
Do vậy khi học lập trình cái khó khăn ban đầu của học sinh chính là tìm thuật
toán để giải bài toán đã cho. Một học sinh muốn tiến sâu, tiến xa trong tương lai
phải có tư duy thuật toán tốt.

1




Bởi vậy làm quen và rèn luyện tư duy thuật toán cho học sinh mới bắt đầu học
lập trình là một yêu cầu thiết yếu. Không nên vội vàng cho học sinh làm việc
trên máy tính luôn khi mới bát đầu học. Có thầy giáo khi dạy tin học cho lớp
chuyên tin đã bỏ ra cả học kỳ để dạy riêng thuật toán.
II.

Phong cách lập trình tốt.

Để có một phong cách lập trình tốt ngoài việc tuân theo các quy chuẩn, còn cần phải tuân theo các
quy ước. Cơ sở cho việc cài đặt một chương trình hiệu quả là: Cách trình bày rõ ràng, sáng sủa nổi
bật được cấu trúc logic của chương trình. Một phần nhỏ trong lập trình là để máy tính có thể đọc
được nó. Phần lớn hơn là viết các mã lệnh cho chương trình chạy được theo đúng chức năng và làm
sao để con người có thể dễ đọc, dễ hiểu nó.
Lợi ích của việc trình bày cẩn thận:
 Thể hiện tốt cấu trúc lôgic của mã lệnh
 Cải thiện khả năng đọc
 Bảo đảm sự chính xác trong các thay đổi
 Các lợi ích hệ quả của các lợi ích trên
-

Chương trình ít mắc lỗi và dễ sửa chữa khi mắc lỗi.

-

Tiết kiệm thời gian sửa lỗi.

-


Tăng khả năng làm việc theo nhóm,

1. Quy ước về cách đặt tên cho các định danh.
Thông thường tùy theo ngôn ngữ và môi trường lập trình, người viết chương trình chọn cho
mình một phong cách nhất quán trong việc đặt tên cho các định danh. Tuy nhiên, nên đặt sao cho
thuận tiện, dễ đọc, dễ nhớ và dễ làm việc, có một số quy tắc cần quan tâm khi đặt tên như sau:
a) Đặt tên cho biến.
Tên biến nên thể hiện được ý nghĩa: thông thường các biến nguyên như i, j, k dùng làm biến
lặp; x, y dùng làm biến lưu tọa độ… Còn những biến lưu trữ khác thì nên đặt tên gợi nhớ: Biến đếm
số lần dùng “Count” hay “Sluong”; biến trọng lượng “weight” hay “Tluong”…. Nếu đặt quá ngắn
ngọn như “c” cho biến đếm hay “w” cho biến trọng lượng thì sau này khi nhìn vào chương trình sẽ
rất khó hiểu và dễ nhầm lẫn, nhưng cũng không nên quá dài dòng như “Demsoluong” hay
“Tinhtrongluong” bởi khi dùng sẽ rườm rà, tốn thời gian viết.


b) Đặt tên hằng: Tất cả các ký tự đều viết hoa.
Ví dụ: Const

MAXN

=

10000;

INPUT

=

‘Baitap.inp’;


c) Đặt tên cho chương trình con: Tên chương trình con thường bắt đầu bằng chữ hoa. Vì chương
trình con thường thực hiện một chức năng nào đó nên tên hay bắt đầu bằng động từ.
Ví dụ:

TimMax( );

GetNum( );

2. Phong cách viết mã nguồn.
a) Quy tắc trình bày tổng thể chương trình:
-

Chương trình nên tách thành nhiều đơn thể (mô _ đun), mỗi đơn thể thực hiện một công việc,

càng độc lập với nhau càng tốt (chương trình con). Điều này sẽ giúp cho chương trình dễ cải tiến và
khi đọc chương trình ta sẽ dễ hình dung được vấn đề đang được thực hiện.
-

Nên sử dụng các tham số khi truyền thông tin cho các chương trình con. Tránh sử dụng các biến

toàn cục để truyền thông tin giữa các chương trình con vì như vậy sẽ làm mất đi tính độc lập giữa các
chương trình con và rất khó khăn khi kiểm soát giá trị của chúng khi chương trình con thi hành.
-

Cách trình bày chương trình càng nhất quán càng dễ đọc, dễ hiểu.

-

Chương trình nên giữ được tính đơn giản, rõ ràng.


-

Chương trình nên thực hiện như một dòng chảy từ trên xuống:
+ Sau đó đến khai báo đơn vị, khai báo hằng, khai báo kiểu, khai báo biến toàn cục, khai báo

chương trình con.
+ Không nên sử dụng Goto vì sẽ phá vỡ tính tuần tự của việc thực hiện chương trình.
b) Quy tắc trình bày dòng lệnh
-

Mỗi câu lênh nên được đặt riêng trên một dòng để chương trình dễ đọc và dễ quan sát cách thực

hiên khi dùng watch để tìm lỗi.
-

Sử dụng tab để canh lề chương trình (các lệnh ngang cấp thì phải tab vào như nhau): Điều này sẽ

giúp chương trình rõ ràng và dễ quản lý.
Ví dụ:
Không nên
For i := 1 to n do Begin Action1;
Action2;

Nên
For i := 1 to n do
Begin

End;

Action1;

Action2;

Nên viết Begin
-

End;
end; rồi viết lệnh vào giữa để tránh thiếu end;

Sử dụng khoảng trắng chương trinh sẽ dễ nhìn hơn:


Ví dụ:
Khó đọc
If (aa:=b*c
TimMax(a,b,c);

Dễ đọc
If ( a < c ) and ( c mod 2 = 0 ) then d := a + c;
a := b * c;
TimMax(a, b, c);

- Nên định nghĩa hằng số: Điều này sẽ tránh việc các con số khó hiểu xuất hiện trong chương trình và
cũng giúp người lập trình dễ kiểm soát chương trình lớn vì giá trị của hằng số khi cần thay đổi chỉ
phải thay đổi một lần duy nhất ở giá trị định nghĩa.
Ví dụ:
Không nên

Nên


……………

Const

For i := 1 to 100 do A[i] := Random(100);
While i<=100 do…

MAXN

=

100;

MAXNUM =

100;

……..
For i :=1 to MAXN do
A[i] := Random(MAXNUM);
While i <= MAXN do …..

Ở đoạn chương trình bên trái rất khó phân biệt các số 100 kia có quan hệ gì với nhau. Tuy nhiên,
trong đoạn chương trình bên phải ta dễ dàng thấy được ý nghĩa của từng giá trị khi thay bằng định
danh. Ngoài ra khi cần thay đổi giá trị của MAXN, MAXNUM thì chỉ cần thay một lần trong phần
định nghĩa.
-

Các biến không nên sử dụng lại với nhiều ý nghĩa khác nhau trong cùng một hàm để tránh sự


nhầm lẫn.
-

Viết chú thích cho chương trình: Biến, hàm khi định nghĩa nên viết chú thích ý nghĩa và chức

năng rõ ràng. Đôi khi các đoạn lệnh thực thi cũng cần giải thích nếu chúng quá phức tạp. Nên viết
chú thích ngắn gọn nhưng đầy đủ và dễ hiểu.
Ví dụ: Var
Procedure

iCount : Integer;

// đếm số cách thực hiện

Try( i : Integer);

// Tìm từ i

Tuy nhiên không phải bất cứ lệnh nào cũng chú thích, việc chú thích tràn lan ngay cả với câu
lệnh đơn giản không có ý nghĩa gì mà còn làm chương trình khó nhìn hơn.
-

Nên viết biểu thức điều kiện mang tính tự nhiên: Biểu thức nên viết dưới dạng khẳng định, việc

viết dưới dạng phủ định sẽ làm khó hiểu.
Ví dụ:
Không nên
If not(a mod 5<>0) then ….

Nên

If a mod 5 = 0 then ….


c) Qui tắc khai báo tên tệp dữ liệu dùng trong chương trình.
Dùng tệp nên khai báo tên têp trước trong phần khai báo hằng:
Ví du:
Const fi=’BAI1.INP’;
Fo=’BAI1.OUT’ ;

3. Tối ưu sự thực thi mã nguồn
Mục đích của việc tối ưu mã nguồn là nâng cao tốc độ xử lý và hạn chế không gian bộ nhớ mà
chương trình chiếm dụng. Thông thường có thể mâu thuẫn giữa tốc độ và không gian lưu trữ, do đó
tùy theo điều kiện cụ thể mà người lập trình có sự lựa chọn thích hợp. Một số thủ thuật sau có thể
giúp người lập trình hình thành nên phong cách lập trình tốt.
-

Lưu tạm giá trị thường sử dụng: Nếu một biểu thức tính toán được dùng nhiều lần thì nên tính kết

quả một lần rồi lưu vào một biến và dùng lại.
Ví dụ:
Không nên

Nên
x2 := x*x;

F:=sqrt(x*x+y*y)+(sqrt(x*x+y*y)*sqrt(x*y)-sqrt(y*y);

y2 := y*y;
p := sqrt(x2 + y2);


If b * b – 4 * a * c >0 then
Begin

F := p + (q * sqrt(x2) – sqrt(y2));
Delta := b * b – 4 * a * c
If delta >0 then

x1 := (-b +sqrt( b * b – 4 * a * c)) / (2 * a);

Begin

x2 := (-b – sqrt(b * b – 4 * a * c)) / (2 * a);

Delta:=sqrt(delta);

end;

x1 := (-b + delta) / (2 * a);
x2 := (-b – delta) / (2 * a);
end;

-

Thay thế một biểu thức bằng một biểu thức tương đương nhưng lợi về thực thi:

Ví dụ: Thay thế các phép nhân chia bằng phép dịch chuyển bit vì các phép xử lý bit tốc độ nhanh hơn
các phép xử lý khác.
Không nên
For i := 1 to n do s:=s*2;


nên
s shl n;


-

Dùng số nguyên thay cho số thực: Do việc xử lý số thực chậm hơn xử lý số nguyên nên ta có thể

dùng số nguyên thay cho số thực có phần lẻ nhỏ.
Vì dụ: Điểm trung bình của học sinh là số thực ta có thể thay bằng số nguyên: DTB là 7.85 thì lưu số
nguyên là 785, khi xuất ra thì chia cho 100.
-

Thoát khỏi vòng lặp khi sớm nhất: Một số trường hợp không cần thiết phải lặp hết toàn bộ mà đã

đạt được mục đích thì có thể thoát khỏi vòng lặp.
Ví dụ:

Không nên
bkt := true;

Nên
bkt := true;

For i := 2 to n do
If n mod i = 0 then

For i := 2 to n do
If n mod i = 0 then


bkt := False;

Begin
bkt := False;
Break;
End;

Hạn chế sử dụng câu lệnh rẽ nhánh: Lệnh rẽ nhánh làm chậm chương trình do ngắt luồng thực thi.
Ví dụ:
Không nên
If x > y then d:=True else d:= False;
-

Nên
d := x>y;

Tránh lãng phí bộ nhớ: Bằng cách sử dụng kiểu dữ liệu nhỏ nhất đủ để lưu trữ. Việc sử dụng tài

nguyên nhiều hơn mức đòi hỏi của chương trình là một thói quen xấu mà người lập trình hay mắc
phải. Hơn nữa tốc độ chương trình sẽ nhanh hơn khi sử dụng kiểu dữ liệu nhỏ hơn.
-

Khai báo biến cục bộ trong phạm vi gần nhất: Khai báo biến cục bộ gần với điểm sử dụng nhất.

Việc khai báo ở phạm vi rộng hơn chỉ làm lãng phí và khó kiểm soát.


-

Giảm số lượng tham số truyền vào hàm: Việc sử dụng hàm có quá nhiều tham số được truyền vào


có thể làm ảnh hưởng đến ngăn xếp dành cho việc gọi hàm. Nhất là trường hợp tham số là kiểu dữ
liệu có cấu trúc. Sử dụng con trỏ hay tham chiếu trong trường hợp này để đơn giản hóa.

4) Kiểm nghiệm chương trình với các bộ test đầy đủ nhất.
- Test đầu bài,
- Các test đơn giản
- Test các trường hợp đặc biệt.
- Test lớn
- Xem lại đề để không bỏ sót trường hợp.
III.

Các dạng toán bồi dưỡng môn tin cho HSG THCS .

Nhóm các bài toán lập trình thường được phân loại theo thuật toán, theo cấu trúc dữ
liệu dùng để giải. Ở bậc THPT dạng toán phong phú hơn rất nhiều do được mở rộng
về CTDL song song với việc mở rộng thuật toán.
Ở bậc trung THCS các bài toán thường chỉ sử dụng các vòng lặp, sử dụng các kiến
thức toán như UCLN , BCNN, số nguyên tố, sự chia hết của các số nguyên,…Các
dạng toán thường gặp là:
 Nhóm các bài toán số học:
 Nhóm các bài toán thao tác trên mảng một chiều.
 Nhóm các bài toán xử lý xâu .
 Các bài toán khác.

1. Các bài toán số học.
Để giải các bài toán về số học giáo viên cần cho học sình ứng dụng nhuần nhuyễn
các kiến thức số học ở THCS chủ yếu dựa vào 2 phép toán DIV, MOD:
 Thuật toán tìm UCLN của 2 số nguyên dương:
Cho 2 số nguyên dương m, n. Tìm UCLN(m,n)

Học sinh thường dùng một trong 2 thuật toán


Thuật toán 1: Sử dụng phép trừ liên tục cho đến khi 2 số bằng nhau:
+ Nhập m, n
+ While m<>n do
If m>n then m:=m-n
Else n:=n-m;
+UCNN:=n;
Thuật toán này chạy chậm: Ví dụ với m=1000000000, n=1 phải chạy
1 tỷ phép toán.
Thuật toán 2: (Đối với HSG nên hướng các em sử dụng thuật toán này)
+ Nhập m, n
+ While n <> 0 do
Begin
r:= m mod n
m:=n;
n:=r;
End;
+UCLN:=m
Với thuật toán này khi m=1000000000, n=1, chỉ mất vài phép toán để tính được
UCLN(m,n).
Để tìm UCLN của dãy a1, a2,…,an, cần lập hàm:
FUNCTION UCLN(a, b: longint): longint;
Khi đó + d:=a1;
+ for i:=2 to n do Begin b:=ai; d:=UCLN(d, b);End;
 Thuật toán tìm BCNN của 2 số:
Ta có BCNN(m,n)= (m * n) div UCLN(m, n).
Ở đây học sinh thường mắc 2 sai lầm sau :
Sai lầm 1 : d :=UCLN(m, n) ;

BCNN :=m*n div d ;
Đúng ra phải là :


BCNN :=m * n (lưu tích m.n)
d := UCLN(m, n) ;
BCNN := BCNN div d
Sai lầm 2 : BCNN(m, n, k) = m*n*k div UCLN(m, n k)
Để tìm BCNN của dãy số nguyên dương a1, a2, …,an (n>=2)
BCNN:=a1; d:=a1;
For i:=2 to n do n do
Begin
b:=ai
BCNN:=BCNN*b;
d:=UCLN(BCNN,b);
BCNN:=BCNN div d ;
End ;
 Kiểm tra số nguyên tố.
Cho số nguyên P. Hỏi P có phải là số nguyên tố không?
Nhiều học sinh lập thuật toán đếm số ước của P. Nếu số ước của P là 2 thì kết
luận P là số nguyên tố. Thuật toán đó không sai nhưng chậm.
FUNCTION Ngto(P:Integer): Boolean;
Var NT:Boolean;
I:integer;
Begin
NT:=P>1;
For i:=2 to Trunc(Sqrt(P)) do
If P mod I =0 then
Begin NT:=False; Break End;
Ngto:=NT;

End;


 Đếm số chữ số của một số, tính tổng các chữ sô
Bài toán : Nhập một số nguyên n. Số n có bao nhiêu chữ sô. Tính tổng các
chữ số của n.
+TongCS:=0; SoCS:=0;
+ While n<>0 do
Begin
Inc(SoCS);
TongCS:=TongCS+ n mod 10;
n := n div 10 ;
End ;


Biểu diễn số tự nhiên n từ hệ đếm thập phân qua các hệ đếm khác và
ngược lại
Bài toán : Cho n là số nguyên dương biểu diễn trong hệ thập phân. Hãy biểu
diễn n trong hệ đếm q – phân ( 1Dùng mảng : array[0..20] of byte ;
+ d:=-1;
+ While n<>0 do
Begin
Inc(d);
a[d]:= n mod q
n:=n div q;
End; { lưu dãy chữ số q- phân theo thứ tự ngược}
+ for i:=d downto 0 do write(a[i]);

Một số bài toán số học.

Bài 1. Phân tích ra thừa số nguyên tố
Cho số tự nhiên n (n>1). Hãy phân tích n thành tích các thừa số nguyên tố.
Ví dụ: Cho n=12 thì n=2.2.3, cho n=300 thì n=2.2.3.5.5
+ Phân tích: Chỉ cần duyệt qua các ước nguyên tố từ bé đến lớn rồi ghi ra.


+ Thuật toán: If Ngto(n) then writeln(n)
Else
Begin
m:=n;
For p:=2 to n div 2 do
If Ngto(p) then
Begin
While m mod p = 0 do write(p,’.’);
m:= m div p;
End;
Bài 2. Rút gọn phân số.
Cho phân số a/ b trong đó a nguyên còn b là số tự nhiên khác không. Hãy tìm 2 số
c, d sao cho phân số c/ d tối giản và a/b=c/d.
+ Phân tích:
Đây là bài toán đơn giản, nhưng phải chú ý số a có thể âm.
+ Thuật toán:
Dau:=1; If a<0 then dau:=-1 ; a:=abs(a);
c:=a div UCLN(a,b); d:=b div UCLN(a, b);
Writeln(dau*c,’/ ‘, d);
Bài 3. Giai thừa.
Cho số tự nhiên n. P=n!. Hỏi:
a/ P có bao nhiêu chữ số không tận cùng.
b/ Số khác 0 tận cùng của P là chứ số nào.
+Phân tích :

a/ Số chữ số 0 cuối cùng chính là số ước bằng 10 của P! mà p!=a.10k=a.2k.5k.
Do số ước 2 nhiều hơn ước 5, nên số 0 tân cùng là k. Vậy ta cần tính số lượng ước
5 của P !


+ Thuật toán: s5:=0;
. For m:=5 to n do
Begin
K:=m;
While k mod 5 = 0 do Begin Inc(s5); k:=k div 5 End;
End;
In ra kết quả : S5.
b/ Câu này dễ mắc sai lầm vừa nhân vừa xóa 0 cuối và chỉ giữ lại chữ số khác 0
cuối cùng.
+ Thuật toán: Giả sử So2, so5 là số lượng ước 2 và ước 5 của P.
S2:=0; S5:=0; P:=1;
For m:=2 to n do
Begin
K:=m;
While K mod 2 = 0 do Begin inc(so2), k:= k div 2 End;
While K mod 5 = 0 do Begin inc(so5), k:= k div 5 End;
P:=P* K mod 10.
End.
For i:= 1 to so2-so5 do Begin p:=p * 2 mod 10
In ra kết quả : P
Bài 4. Tính tổng chữ số. (Đê thi HSG thành phố Hà nội năm 2010)
Một quyển sách có n trang. Hỏi
a/ Tổng tất các chữ số đã ghi trên các trang sách.
b/ Mỗi chũa số xuất hiện bao nhiêu lân.
Thuật toán :

+ Lập hàm TongCS(K) để tính tổng các chữ số trong K
+ Dùng mảng a[0], a[1],…,a[9], trong đó a[i] số lần xuất hiện của chữ số i:
+ Sum:=0; fillchar(a, sizeof(a),0);


+ For m:=1 to n do
Begin
K:=m;
Sum:=Sum+TongCS(K);
While K <> 0 do
Begin
Inc( a[ k mod 10])
K:=K div 10
End;
In ra kết quả: Sum, a[0],…, a[9]
Bài 5. Phân tích (Thi HSG MOSKVA)
Cho số tự nhiên n. Hãy phân tích n =A+B sao cho UCLN(A, B) là lớn nhất.
Với 2≤ n≤ 109.
Bài .6
Số nguyên tố.
Cho một số tự nhiên n>1. Tìm số k nguyên tố không vượt quá n trong các trường hợp
sau:
a) k lớn nhất.
b) k có tổng các chữ số lớn nhất .
c) k là số đối xứng lớn nhất. ( k là số đối xứng nếu đọc số đó từ trái qua phải hay
từ phải qua trái đều như nhau. Ví dụ: các số 373, 3, 979…là các số đối xứng)
Input cho trong tệp NT.INP:- gồm một dòng duy nhất ghi số nguyên n
(1Output ghi vào tệp NT.OUT: gồm 1 dòng, ghi 3 số tương ứng cách nhau bởi dấu cách
là đáp số của câu a, b, c. Câu nào không tìm được kết quả thì ghi số 0 thay thế.

Ví dụ:
NT.INP
NT.OUT
100
97 89 11
Bài 7. Số siêu nguyên tố. (Đề thi HSG Thành phố)
Số P gọi lầ số siêu nguyên tố, nếu nó nguyên tố và khi ta lần lượt bỏ các chữ số ở
hàng đơn vị từ tái qua phải thì số mới nhận được vẫn là một số nguyên tố.
Ví dụ: 239 là số siêu nguyên tố vì 239 là số nguyên tố và 23, 2 cũng là các số nguyên
tố , còn 431 là số nguyên tô, 43 cũng là số nguyên tố, nhưng 4 không nguyên tố nên


431 không phải là số siêu nguyên tố. Cho một số n (0siêu nguyên tố có n chữ số .
Lời giải
• Phương án 1: Duyệt toàn bộ:
+ Tìm số nhỏ nhất lớn nhất có n chữ số
Chẳng hạn với n=3 thì số nhỏ nhất và lớn nhất có 3 chữ số là: n1=100 và n2=999
+ Dùng một biến chạy p:
For p:= n1 to n2 do
If p thỏa mãn then tăng biến đếm.
+ Thuật toán này cũng được 40 % số test
• Thuật toán tốt.
+If n=1 thì a[1]:=2;[2]:=3; a[3]:=5, a[4]:=7; slg:=4
+ If n>1 then
Begin c[1]:=1; c[2]:=3; c[3]:=7; c[4]:=9;scs:=1;
Repeat inc(scs); tg:=0; fillchar(b, sizeof(b),0)
For k:=1 to slg do For g:=1 to 4 do
Begin if NT(a[k]*10+c[g]) then
Begin inc(tg); b[tg]:= NT(a[k]*10+c[g]) End

End;
a:=b;Slg:=tg; tg:=0;
Until scs=n.
End; {kết quả là Slg}

Bài 8.
Phân số

Phân số ( Đề thi HSG thành phố Hà nội)
p

q

( p, q là 2 số nguyên dương) gọi là phân số đúng nếu

là phân số tối giản nếu UCLN(p,q)=1
Yêu cầu: Cho trước số nguyên n (3≤ n ≤ 50000000).

p

q

<1. Còn

p

q

gọi



a) Tính số lượng các phân số đúng, tối giản
b) Tìm phân số đúng, tối giản

p

q lớn

p

q mà

p+q=n.

nhất mà p+q=n.

2. Nhóm các bài toán mảng.
Trong phần này gv cần cung cấp cho học sinh một số kỹ năng cơ bản khi thao
tác trên mảng như: Tìm phần tử MAX, MIN, sắp xếp đơn giàn, kiểm tra tinh
đơn điệu của dãy, tìm kiếm trên dãy…
Bai1. Trong một buổi sinh hoạt câu lạc bộ Tin học của Cung thiếu nhi Hà Nội, thầy
giáo ra một bài toán như sau: Từ số hạng đầu tiên của dãy số Fibonacci (là dãy số có
quy luật: số hạng thứ nhất và thứ hai bằng 1, từ số hạng thứ ba trở đi bằng tổng hai số
hạng đứng ngay trước nó) thành lập dãy số mới gồm số bằng cách lần lượt thay mỗi
số hạng bằng số dư của số hạng đó khi chia cho 100.
Ví dụ, với ta có 13 số hạng đầu tiên của dãy số Fibonacci là:
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233
Dãy số mới nhận được sau khi thay là:
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 44, 33
Để kiểm tra bài làm, thầy giáo yêu cầu các bạn trả lời hai thông tin sau:


Số hạng thứ trong dãy mới là số nào?


Có bao nhiêu giá trị khác nhau trong dãy số mới?

Nhập vào từ file FIBO.INP số nguyên dương n duy nhất.
Xuất ra màn hình:
+ Dòng 1: in ra số hạng thứ trong dãy mới.
+ Dòng 2: in ra số lượng các giá trị khác nhau trong dãy mới.
Ví dụ:
Nhập
Kết quả ra màn hình Giải thích
33
Số hạng thứ 13 trong dãy mới là số 33
12
Có 12 giá trị khác nhau trong dãy số mới
Lời giải:
• +Dùng mảng : a[0], a[1], a[2],…, a[99];
• A[i]=0 nếu I không xuất hiện trong dãy rút gọn), a[i]=1 nếu I xuất hiện trong
dãy.
+ If (n=1) or (n=2) then writeln (1,’ ‘, 1);


Else Begin a:=1; b:=1; d:=2;
Repeat Inc(d);
I
c:=(a+b) mod 100; a:=b;b: =c;
If a[c] =0 then a[c]:=1;
Until d=n;

End; {In ra C, a[0]+a[1]+…+a[99]}
Bài 2 Tổng max.
Cho dãy n số nguyên dương a1, a2,…an. Hãy tìm 2 số ai, aj, sao cho i≠j và ai+aj đạt
max.
Lời giải:
• Thuật toán 1: Duyệt toàn bộ:
+ Max:=a1+a2;
+ For i:=1 to n-1 do
For j:=i+1 to n do
If MaxThuật toán này có độ phức tạp O(n2)
Khi n=10000, thuật toán không hiệu quả
• Thuật toán 2 : Sắp xếp
+ Sắp xếp giảm dần a1, a2, a3,….
+Max:=a1+a2.
Độ phức tạp của TT này là O(n2). Tuy nhiên học sinh biết PP sắp xếp nhanh thì tốc độ
xử lý tốt hơn (O(nlogn))
• Thuật toán 3. Tìm số lớn thứ nhất thứ nhì
+ maxi:=1; for I:=2 to n do if maxi+maxj:=1;
for I:=2 to n do if maxjĐáp số : m+a[maxj]
• Thuật toán 4. (Xử lý luôn khi đọc dữ liệu)
+Readl(f,n) {n >1}; Read (f, a,b);
{gọi max1, max2 là số lớn và bé trong a,b}
+If a>b then Begin max1:=a; max2:=b End
Else Begin max1:=b; max2:=a End


+ For i:=3 to n do

Begin
Read(f, c);
If c>= max1 then
Begin max2:=max1; max1:=c End
Else If c>= max2 then max2:=c;
End; { Đáp số là max1+max2
Bài 3. Bao nhiêu điểm.
Trong một cuộc thi đấu thể thao n người tham gia . Người thứ I có điểm là ai . Biết
rằng có đủ các giải nhất ,nhì, ba và những người có điểm ngang nhau có giải như
nhau và ngược lại. An được giảI 3. Hỏi số điểm của An là bao nhiêu.
Ví dụ: Input n=6, a: 10 9 1 7 3 10 7
Output: 7
Lời giải:







Thuật toán:
+sắp xếp giảm dần
+i:=1;
+ While a[i+1]=a[i] do i:=i+1;
+ i:=i+1;
+While a[i+1]=a[i] do i:=i+1;
Đáp số : a[i+1]

3. Nhóm các bài toán xử lý xâu.
Để giải các bài toán về xâu cần cho học sinh nắm vững các hàm, thủ tục xử lý

xâu như hàm COPY(), LENGTH(), INSERT(), STR() , VAL()…
Bài 1. Tìm số (Đề thi HSG thành phố Hà nội 2011)
Cho một xâu S, trong đó có chứa một số cụm số. Không có quá 6 chữ số liên tuc
trong S.
Hãy tìm xâu con của S, biểu diễn một số nguyên tố lớn nhất.


Ví dụ S = ‘tesst1234#password5426’. Số cần tìm là 23.

Bài 2.

Mật khẩu

Một mật khẩu được gọi là an toàn loại 1 nếu nó có ít nhất 6 ký tự và trong đó phải
có đủ 3 loại : chữ cái hoa, chữ cái thường, chữ số. Mật khẩu gọi là an toàn loại 2
nếu thêm điều kiện nó chứa 2 chữ cái hoa khác nhau, 2 chữ cái thường khác nhau
và có 2 chữ số khác nhau.
Cho trước một xâu S dài không quá 255 ký tự bao gồm chữ cái hoa, chữ cái
thường và chữ số.
Yêu cầu:
a). Trong S có bao nhiêu chữ cái hoa khác nhau, chữ cái thường khác nhau và
bao nhiêu chữ số khác nhau?
b). Chọn một xâu con (gồm các ký tự liên tục) của S có độ dài ngắn nhất sao
cho xâu con vừa chọn có thể dùng làm một mật khẩu an toàn loại 1.
c). Chọn một xâu con (gồm các ký tự liên tục) của S có độ dài ngắn nhất sao
cho nó có thể dùng làm một mật khẩu an toàn loại 2.
Input cho trong tệp MK.INP gồm một dòng duy nhất ghi xâu S.
Output ghi vào tệp MK.OUT : - Dòng 1 ghi 3 số nguyên (cách nhau bới dấu
cách) là đáp số tương ứng của câu a). - Dòng 2 ghi 2 số là độ dài ngắn nhất của
mật khẩu loại 1 và loại 2 tương ứng tìm được (nếu không có ghi số 0).

Ví dụ:
MK.INP
dserwGasddasddda2453dssa
Asdg5HgHvH4c

MK.OUT
1 6 4
12 0
25 2
6 11

BÀI 3. SẮP XẾP TĂNG
Cho xâu S chứa không quá 255 ký tự chỉ gồm các chữ cái tiếng anh thường và chữ số,
trong đó có ít nhất một chữ số. Các chữ số kế tiếp nhau trong S tạo thành một số tự
nhiên có nghĩa, tức là không xét đến các chữ số 0 vô nghĩa ở đầu.
Yêu cầu:
a/ Tính số lượng các chữ số khác nhau có mặt trong dãy.
b/ Sắp xếp tăng dần các số trong xâu sau khi loại bỏ các số 0 vô nghĩa ở đầu mỗi số.
Các kí tự khác giữ nguyên thứ tự. Giả thiết mỗi xâu con của S có không quá 6 chữ số
liên tục.
Dữ liệu: Vào từ tệp văn bản SXT.INP gồm một dòng duy nhất ghi xâu S.
Kết quả: Ghi ra tệp văn bản SXT.OUT:


- Dòng 1 ghi số lượng các chữ số khác nhau có mặt trong dãy.
- Dòng 2 ghi xâu S sau khi đã sắp xếp lại các số, các kí tự khác số giữ nguyên thứ tự.
Ví dụ:
SXT.INP
SXT.OUT
SXT.INP

SXT.OUT
Lời giải:
7
t994a0046ui00t148 6
a/a212921hda456e3
Dùng mảng a[0..9] , a[i]=0 nếu I không có mặt, a[i]=1 nếu I có mặt. b/
x
t0a46ui148t994x
+bTách số và chèn dấu a3hda456e212921
* vào vị trí số:
so[1]=994, so[2]=0046,b s0[3]=00, so[4]= 148
 S=t*a*ui*t*x
+ Chuẩn và sắp sếp tăng:
so[1]=0, so[2]=46, so[3]=148, so[4]= 994
+ Lần lượt thay dấu * bởi so[1], so[2],…
=> S=t0a46ui148t994x .



×