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

Một số giải pháp phân loại và tối ưu cho các bài toán dãy con trong ôn luyện học sinh giỏi môn tin học

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 (153.51 KB, 21 trang )

MỤC LỤC

1


1. Mở Đầu
1.1. Lí do chọn đề tài

Qua nhiều năm giảng dạy và ôn đội tuyển học sinh giỏi môn Tin học tôi
nhận thấy trong các đề thi học sinh giỏi bài tập về dãy con gần như năm nào
cũng có ở các mức độ khó và dễ khác nhau. Để giải quyết các bài tốn về dãy
con này có thể phải nhận biết vận dụng linh hoạt các thuật toán như: Quay lui vét cạn, chặt nhị phân và đặc biệt là phương pháp quy hoạch động trên mảng
một chiều, hai chiều được vận dụng rất nhiều để giải quyết.
Nội dung sách giáo khoa Tin học 11 chỉ giới thiệu về mảng 1 chiều và 1
số bài toán cơ bản liên quan tới mảng 1 chiều và để học sinh vận dụng vào giải
quyết các bài thi học sinh giỏi là rất khó.
Tài liệu ơn luyện học sinh giỏi viết về dãy con cũng không nhiều, đa số là
lồng ghép trong các tài liệu về quy hoạch động hay các chuyên đề về quay lui
vét cạn… Học sinh khi giải quyết các bài toán dãy con thường chưa đưa ra được
các thuật toán tối ưu nên dẫn đến mất test, điểm khơng cao vì vậy tơi chọn đề tài
“Một số giải pháp phân loại và tối ưu cho các bài tốn về dãy con trong ơn
luyện học sinh giỏi môn Tin học” làm sáng kiến kinh nghiệm trong năm học
2020-2021 với mục đích được trao đổi các phương pháp mà tơi đã và đang áp
dụng rất có hiệu quả cùng các bạn đồng nghiệp và cũng hy vọng phương pháp
này sẽ được bổ sung, hoàn thiện và sử dụng THPT Nguyễn Quán Nho nói riêng
và các trường THPT trên địa bàn của tỉnh Thanh Hóa nói chung.
1.2. Mục đích nghiên cứu.

Việc dạy cho học sinh niềm đam mê và khả năng tư duy lập trình là điều
khơng thể thiếu đối với việc bồi dưỡng học sinh giỏi môn Tin học. Tơi viết về đề
tài này với mục đích:


- Cùng trao đổi với các bạn đồng nghiệp về cách dạy học sinh bước đầu
vào học lập trình mơn Tin học và xử lí tốt các bài tốn về dãy con.
- Giúp học sinh có thêm một tài liệu để tham khảo trong quá trình học lập
trình.
- Giúp anh chị em đồng nghiệp trong trường và ở các trường phổ thông
trên địa bàn tỉnh có thêm một tài liệu để ơn tập thi giáo viên giỏi và phục vụ
công tác bồi dưỡng học sinh giỏi.
1.3. Đối tượng nghiên cứu.

Các dạng bài tốn, thuật tốn về dãy con trong lập tình Pascal của học
sinh THPT trong việc ôn luyện đội tuyển học sinh giỏi.
1.4. Phương pháp nghiên cứu.

-Phương pháp nghiên cứu lý luận: Nghiên cứu các tài liệu, sách báo.
2


-Phương pháp điều tra thực tiễn: Quan sát việc học của học sinh trong quá
trình khai thác các bài tập sách giáo khoa, sách bài tập và các đề thi học sinh
giỏi.
-Phương pháp thực nghiệm sư phạm trên đối tượng là học sinh khá giỏi
môn Tin học THPT.
2. Nội dung sáng kiến kinh nghiệm
2.1. Cơ sở lí luận của sáng kiến kinh nghiệm.

Căn cứ vào cấu trúc đề thi học sinh giỏi tỉnh cấp THPT các mơn văn hóa
nói chung và mơn Tin học nói riêng của Sở giáo dục và đào tạo Thanh Hóa.
Trường THPT Nguyễn Quán Nho là trường xa trung tâm, chất lượng
tuyển sinh đầu vào thấp, khu vực tuyển sinh hạn chế (gồm các xã Thiệu Quang,
Thiệu Giang, Thiệu Thịnh, Thiệu Hợp, Định Công, Định Thành) nên số lượng

học sinh mũi nhọn ít, mỗi năm nhà trường chỉ có 1 lớp khoa học tự nhiên, việc
lựa chọn học sinh giỏi của hầu hết các môn đều lấy ở lớp này nên trường tôi năm
nào học sinh giỏi môn Tin đều là những em phải thi 2 mơn (Tốn-Tin) hoặc (LíTin).
Mơn Tin học chưa được học ở cấp 2 lại là môn phụ không thi tốt nghiệp,
đại học nên học sinh không chú trọng học tập nghiên cứu. Là mơn khơng có dạy
thêm nên việc dạy đội tuyển cũng gặp rất nhiều khó khăn. Chính vì thế việc hệ
thống, phân loại tối ưu các dạng bài trong ôn luyện để học sinh hiểu dễ, hiểu sâu
và dễ dàng trong việc ôn luyện là rất cần thiết.
Cách lựa chọn thuật tốn tối ưu cho từng bài: “Nói về độ phức tạp của
thuật tốn thì độ phức tạp về thời gian là quan trọng nhất, bởi vì nếu một thuật
toán cho ra một kết quả đúng nhưng thời gian thực hiện thuật toán cần một
khoảng thời gian lớn đến nỗi khơng thể chấp nhận được (Ví dụ bài tốn tháp Hà
Nội nếu dùng đệ quy để tính tốn thì với tốc độ máy tính hiện nay phải giải nó
khoảng vài ngàn năm). Do đó yêu cầu thời gian được đưa ra đầu tiên. Thuật tốn
được gọi là hay thì phải có thời gian thực hiện ngắn và tiết kiệm tài nguyên máy
tính. Sự hao phí tài nguyên máy tính liên quan đến phần cứng máy tính. Vì vậy
mà những thuật tốn đưa ra thường lấy thời gian để tính độ phức tạp hơn là tài
nguyên (vì mỗi máy khác tài ngun). Vì vậy, độ phức tạp của thuật tốn là thời
gian thực hiện của thuật toán.”
2.2. Thực trạng vấn đề trước khi áp dụng sáng kiến.

Khi tìm hiểu và lập trình với Pascal, ban đầu các em rất hứng thú nội
dung học và bài tập sách giáo khoa nội dung đơn giản. Các bài toán về dãy con
trong đề thi lại đa dạng yêu cầu tư duy cao, vận dụng linh hoạt nên học sinh thấy
khó phân loại và áp dụng kĩ thuật lập trình cho từng bài cụ thể.
3


Trong q trình ơn luyện các bài tập dãy con tôi giảng dạy cho học sinh
theo từng bài đơn lẻ chưa có hệ thống tuy nhiên bài tập dãy con rất đa dạng và

có nhiều cách giải khác nhau.
Các em tham gia đội tuyển thường là những em học khá các môn tự
nhiên, các em giải quyết vấn đề theo hướng dễ hiểu nhất mà chưa ưu tiên lựa
chọn các thuật toán tối ưu về mặt thời gian thực hiện dẫn đến các em làm bài
nhưng kết quả không cao.
2.3 Các giải pháp đã áp dụng để giải quyết vấn đề.
2.3.1. Giải pháp 1: Cung cấp lý thuyết về mảng 1 chiều, chuyên đề dãy con.
Để thực hiện giải pháp này tôi yêu cầu học sinh nắm thật kỹ các kiến thức
về kiểu mảng 1 chiều được trình bày trong sách giáo khoa Tin học 11. Ngồi ra,
tơi cung cấp thêm những kiến thức về dãy con, các thao tác cơ bản, cách duyệt
trên dãy con.
* Mảng 1 chiều
1. Khai báo:
“- Khai báo trực tiếp:
VAR <Tên biến> : ARRAY [<Tập chỉ số>] OF <Kiểu phần tử>;
Ví dụ: Khai báo biến a là mảng 1 chiều gồm 1000 phần tử kiểu số nguyên.
Var a : array [1 .. 1000] of longint;
- Khai báo gián tiếp:
TYPE <Tên kiểu> = ARRAY [<Tập chỉ số>] OF <Kiểu phần tử>;
VAR <Tên biến> : <Tên kiểu>;
Ví dụ: Khai báo biến a là mảng 1 chiều gồm 1000 phần tử kiểu số nguyên.
Type mang = array [1 .. 1000] of longint;
Var a : mang;
Ta nhận thấy khai báo trực tiếp thì ngắn gọn hơn khai báo gián tiếp. Tuy
nhiên có 1 số trường hợp ta khơng thể khai báo trực tiếp mà phải khai báo gián
tiếp. Chẳng hạn ta không thể khai báo trực tiếp cho các tham số trong chương
trình con.
2. Truy xuất các phần tử:
Ta không thể truy xuất trực tiếp đến các biến kiểu mảng 1 chiều mà ta phải
truy xuất đến từng phần tử của nó.

Mỗi phần tử của mảng 1 chiều được truy xuất thông qua tên biến mảng cùng
với chỉ số của nó được đặt trong cặp [ ].
Ví dụ:
+ a[1] : truy xuất đến phần tử thứ 1 trong mảng a
4


+ a[5] : truy xuất đến phần tử thứ 5 trong mảng a”. [1]
* Dãy con:
“ Dãy con là dãy các phần tử liên tục thuộc một dãy có trước (dãy mẹ)
thỏa mãn một tính chất nào đó. (dãy con được lưu dưới dạng mảng 1 chiều).
- Để quản lí một dãy con cần một chỉ số (nơi bắt đầu dãy con) và độ dài của
dãy.
- Một cách quản lí khác là chỉ số đầu và chỉ số cuối.
- Để xây dựng một dãy con cần:
- Xây dựng giá trị ban đầu.
- Duyệt qua các phần tử của dãy, nếu:
Thỏa điều kiện, tăng độ dài thêm 1 ngược lại:
+ Nếu dãy con đang xét cần lưu thì: Lưu lại độ dài, chỉ số đầu dãy, xác
định lại độ dài, chỉ số đầu của dãy mới.
+Nếu dãy con đang xét không cần lưu thì: Xác định lại độ dài, chỉ số đầu
của dãy mới.
- Để duyệt qua tất cả các dãy con của một dãy gồm n số ta dùng thuật toán vét
cạn sau:
For i:= 1 to n do
For j:= 1 to n-i+1 do xét dãy con bắt đầu từ vị trí thứ i có độ dài j.” [2]
Thời gian thực hiện giải pháp 1: Là 1 buổi, giáo viên cho học sinh nhắc lại
kiến thức mảng 1 chiều đã học trong sách giáo khoa, làm bài tập vận dụng để
nắm chắc kiến thức. Đưa ra khái niệm dãy con, các thao tác cơ bản trên dãy con,
làm một số ví dụ đơn giản.

Kết quả sau khi thực hiện giải pháp 1: Học sinh nhớ thao tác, hiểu bản chất về
mảng, vận dụng được để giải được các bài tập cơ bản.
2.3.2 Giải pháp 2: Cung cấp một số thuật toán cơ bản trên mảng
-Dạng 1: Duyệt để tìm kiếm trên mảng
Thuật tốn 1: Tìm kiếm tuần tự
Thuật tốn 2: Tìm kiếm nhị phân
-Dạng 2: Sắp xếp mảng theo thứ tự tăng hoặc giảm dần
Có nhiều thuật tốn sắp xếp như: Sắp xếp đơn giản, sắp xếp nổi bọt, sắp xếp
chèn, sắp xếp nhanh…
-Dạng 3: Chia mảng thành k dãy con thỏa mãn điều kiện cho trước
Một mảng gồm n phần tử, bài toán đặt ra là cắt mảng thành k dãy con thỏa mãn
1 số điều kiện nào đó là bài toán được xử dụng nhiều trong xử lý mảng.
Thời gian thực hiện giải pháp 2: Là 2 buổi, giáo viên giới thiệu các thuật toán
cơ bản trên mảng 1 chiều, cách vận dụng từng thuật toán cho bài tập cụ thể. Giới
thiệu một số bài trong các đề thi cụ thể
Kết quả sau khi thực hiện giải pháp 2: Học sinh biết cách áp dụng các thuật
toán cơ bản trên mảng phù hợp với yêu cầu bài toán.
2.3.3 Giải pháp 3: Phân loại các bài toán về dãy con
5


Trong qua trình nghiên cứu tài liệu, sách báo: Tài liệu tập huấn bồi dưỡng
HSG năm 2015 và năm 2017 của Sở GD&ĐT Thanh Hóa (nguồn nội bộ), tìm và
giải đề thi HSG các tỉnh cũng như tỉnh Thanh Hóa môn Tin học và tra cứu các
bài tập về dãy con trên các diễn đàn học Pascal. Tôi đã tập hợp và phân loại các
bài toán về dãy con và đây cũng là giải pháp chủ yếu giúp tôi ôn tập có hiệu quả
phần dãy con nhằm nâng cao chất lượng bồi dưỡng học sinh giỏi môn Tin học.
2.3.3.1 Dãy con gồm các phần tử liên tiếp
Dãy con là dãy các phần tử liên tục thuộc một dãy có trước thỏa mãn một
tính chất nào đó. Giải thuật cơ bản áp dụng cho bài toán dãy con liên tục là sử

dụng 2 vòng lặp WHILE lồng nhau để duyệt dãy số một lần từ đầu đến cuối dãy.
Ngồi ra có thể dùng phương pháp quy hoạch động.
“Trong những bài toán về mảng một chiều thì bài tốn tìm dãy con thỏa mãn
điều kiện nào đó là một bài tốn tương đối hay, thường được chọn làm bài cấp
độ 2 trong đề thi học sinh giỏi Tin học vòng huyện hay vịng tỉnh. Dạng bài tốn
này địi hỏi học sinh khi lập trình phải có kĩ năng tương đối thành thạo trong
việc xử lí mảng một chiều.” [3].
Bài tốn 1:
Cho một dãy A gồm N số nguyên (a1, a2,…, aN). Dãy con ai, ai+1,…,
aj(1≤i≤j≤N) là dãy được tạo từ các phần tử liên tiếp của dãy A bắt đầu từ phần tử
i và kết thúc ở phần tử j.
Yêu cầu: Hãy tìm độ dài và liệt kê giá trị mỗi phần tử của dãy con dài nhất tạo
thành cấp số cộng có cơng sai d.
Dữ liệu vào: File văn bản daycon.inp gồm:
- Dòng đầu ghi giá trị N, d (2≤N≤10000; 0≤d≤500 ).
- Dòng sau gồm N số nguyên (a1, a2,…, aN) (-106≤ai≤106) mỗi số cách
nhau một dấu cách.
Dữ liệu ra: File văn bản daycon.out gồm
- Dòng đầu ghi độ dài dãy con và số dãy con thỏa mãn.
- Dòng tiếp theo ghi giá trị các phần tử dãy con.
(Chú ý: Nếu khơng có dãy con nào thỏa mãn thì ghi 0)
Ví dụ:
Daycon.inp
83
36952584

Daycon.out
32
369
258


Cách 1: Khi gặp bài tốn này thơng thường học sinh sử dụng phương pháp vét
cạn các dãy con như sau:
*Thuật toán:
For i:=1 to n do
For j:=1 to n-i+1 do
6


Begin
{Xét tất cả các dãy con bắt đầu từ vị trí i có độ dài j}
end;
hoặc For k:=1 to n do
For j:=1 to n-k+1 do
begin
j:=i+k-1;
{Xét tất cả các dãy con bắt đầu từ vị trí i đến vị trí j với độ dài k}
end;
*Code tham khảo:
Type km=array[0..10001] of longint;
Var a,cs:km; f,g:text;dmax,i,j,n,k,d:longint;
Procedure inday(b:km;m,l:longint);
Var i:integer;
Begin for i:=m to m+l-1 do write(b[i],' '); writeln;
End;
Function kt(b:km;m,l:integer):boolean;
Var i:integer;
Begin for i:=m to m+l-2 do
if b[i+1]-b[i]<>d then exit(false); exit(true);
End;

BEGIN
assign(f,’daycon.inp’);reset(f);
assign(g,’daycon.out’);rewrite(g);
readln(f,n,d); for i:=1 to n do read(f,a[i]);
{tim do dai va chi so dau day con thoa man}
dmax:=0; k:=0;
for i:=1 to n-1 do
for j:=2 to n-i+1 do
if kt(a,i,j) then
begin
if j>dmax then begin dmax:=j;k:=0; end;
if j=dmax then begin k:=k+1;cs[k]:=i; end;
end;
{in ket qua}
if dmax=0 then write(g,'0')
else begin writeln(g,dmax,' ',k);
for i:=1 to k do inday(a,cs[i],dmax);
end; close(f); close(g);
END.
Với cách này chỉ lấy được 40% số điểm câu này. Vì một số test có dữ liệu
lớn chạy quá thời gian.
Cách 2: Thuật toán duyệt qua các phần tử của dãy mẹ.
*Thuật toán:
7


- Khởi tạo: dmax=1; dem=1; dau=1; a[n+1]=a[n]+d+1;k=0;
{Biến dmax lưu độ dài max dãy, biến dau lưu giá trị đầu mỗi dãy, biến k lưu số
lượng dãy con thỏa mãn}
- For i:=1 to n do

Nếu a[i+1]-a[i]=d thì tăng biến dem, ngược lại:
Nếu dem>dmax thì begin dmax=dem;k=1;dem=1;cs[k]=dau;dau=i+1;
end, ngược lại:
Nếu dem=dmax thì begin inc(k);cs[k]=dau;dau=i+1;dem=1;
end, ngược lai: begin dem=1; dau=i+1; end;
*Code tham khảo:
Type km=array[0..10001] of longint;
Var a,cs:km; f,g:text;dmax,i,j,n,k,d:longint;
BEGIN
assign(f,’daycon.inp’);reset(f);
assign(g,’daycon.out’);rewrite(g);
readln(f,n,d);
for i:=1 to n do read(f,a[i]);
{tim do dai dmax va chi so dau cac day con thoa man}
k:=0;dmax:=1;dem:=1; dau:=1;a[n+1]:=a[n]+d+1;
For i:= 1 to n do
begin
if a[i+1]-a[i]=d then inc(dem)
else
begin if dem>dmax then
begin dmax:= dem; k:=1;cs[k]:=dau; dem:=1;dau:=i+1; end
else
if dem=dmax then
begin inc(k);cs[k]:=dau;dau:=i+1;dem:=1;end
else begin dem:=1;dau:=i+1;end;
end;
end;
{in ket qua}
if dmax=1 then write(0) else
begin writeln(g,dmax,' ',k);

for j:=1 to k do
Begin for i:=cs[j] to cs[j]+dmax-1 do write(g,a[i],' '); writeln;
End;
end;
close(f); close(g);
END.
Với cách này có thể lấy được 100% số điểm câu này. Tuy nhiên nếu dữ
liệu vào lớn như n=108 thì sẽ có một số test yếu nên không lấy được điểm tối
đa.
Cách 3: Dùng quy hoạch động.
8


*Thuật toán
- Gọi f[i] là độ dài dãy con tạo thành cấp số cộng cơng sai d có chỉ số cuối là i.
- f[1]=1 ;
- Công thức quy hoạch động :
Nếu a[i+1]-a[i]=d thì f[i+1]=f[i], ngược lại f[i+1]=1.
- Kết quả bài toán: Max(f[i+1]) với i=1,2,...,n-1.
*Code tham khảo
Type km=array[0..10001] of longint;
Var f,a,cs:km; s,g:text;dmax,i,j,n,k,d:longint;
BEGIN
assign(s,’daycon.inp’);reset(s);
assign(g,’daycon.out’);rewrite(g);
readln(s,n,d); for i:=1 to n do read(s,a[i]);
f[1]:=1; dmax:=0; k:=1;
for i:=1 to n-1 do
begin
if a[i+1]-a[i]=d then f[i+1]:=f[i]+1

else f[i+1]:=1;
if f[i+1]>dmax then begin dmax:=f[i+1];k:=1;cs[k]:=i+1; end
else if f[i+1]=dmax then begin inc(k);cs[k]:=i+1; end;
end;
{in ket qua}
if dmax=1 then write(g,'0')
else begin writeln(g,dmax,' ',k);
for j:= 1 to k do
begin for i:=cs[j]-dmax+1 to cs[j] do write(g,a[i],' '); writeln;
end;
end;
close(s); close(g);
End.
Dễ dàng nhận thấy cách 3 là tối ưu hơn cả mà chương trình ngắn gọn dễ
cài đặt phù hợp với năng lực học sinh trường tôi. Do vậy giải các bài tập dạng
này ta nên lựa chọn cách thứ 3. Cách này có thể lấy được điểm với dãy có số
phần tử lớn lên đến n=10 8. (Tuy nhiên học sinh có thể lựa chọn cách 2 để giải
quyết bài tốn thì cũng lấy được 100% số điểm nếu n<108).
Bài tốn 2: Tính tổng của dãy số (Tài liệu lưu hành nội bộ)
Cho dãy số nguyên gồm n phần tử a1, a2, …, an và hai số nguyên dương
p và q (1 ≤ p ≤ q ≤ n).
Yêu cầu: Hãy tính tổng của các phần tử liên tiếp từ ap … aq.
Dữ liệu: Vào từ file văn bản SUM.INP có cấu trúc như sau:
- Dòng 1: Ghi số nguyên dương n và k, hai số được ghi cách nhau một dấu cách.
(1 ≤ k, n ≤ 105)
9


- Dòng 2: Ghi n số nguyên a1, a2, …, an, các số được ghi cách nhau ít nhất một
dấu cách (-32000 ≤ ai ≤ 32000).

- Dòng thứ i trong k dòng tiếp theo: Mỗi dòng ghi hai số nguyên dương pi và qi,
hai số được ghi cách nhau một dấu cách (1 ≤ pi ≤ qi ≤ n).
Kết quả: Ghi ra file văn bản SUM.OUT theo cấu trúc như sau:
- Dữ liệu được ghi trên k dòng: Dòng thứ i ghi một số nguyên là tổng giá trị của
các phần tử trong đoạn
Ví dụ:
SUM.INP
5
2
1
2
4

3
9 -3 5 8
5
3
4

SUM.OUT
21
6
5

*Thuật tốn:
Gọi S[i] là tổng giá trị các phần tử a1, a2, …, ai
Ta có cơng thức quy hoạch động để tính S[i] như sau:
S[i] := S[i - 1] + A[i];
Như vậy, việc tính T[n] được thực hiện bằng vịng lặp:
S[0] := 0;

For i:=1 to n do
S[i] := S[i - 1] + A[i];
Kết quả: Tổng các phần tử liên tiếp từ ap đến aq được tính theo cơng
thức:
Sum := S[q] - S[p-1];
*Code tham khảo:
var n,k: longint;f,g:text;
i, p, q: longint;
s: array[0..100001] of int64;
a: array[1..100001] of integer;
BEGIN
assign(f,’sum.inp’); reset(f);
assign(g,’sum.out’); rewrite(g);
readln(f,n,k);
s[0]:= 0;
for i:= 1 to n do
begin
read(f,a[i]);
s[i]:= s[i-1]+ a[i];
end;
for i:= 1 to k do
10


begin
readln(g,p, q);
writeln(g,s[q] - s[p-1]);
end;
close(f); close(g);
END.

Bài tốn 3. SUBARRAY ( Trích đề thi Nghệ An 2013-2014)
Cho một dãy số nguyên a 1, a2, …. aN và số nguyên dương K. Dãy con a i, ai+1,
… aj (1<=i<=j<=N) là dãy được tạo từ các phần tử liên tiếp của dãy A, bắt đầu
từ phần tử i và kết thúc ở phần từ j.
u cầu: Tìm số lượng dãy con của A có ít nhất K phần tử bằng nhau.
Dữ liệu: Vào từ file văn bản SUBARR.INP:
Dòng đầu tiên cứa 2 số nguyên dương N, K (1<=k<=N<=4.10 5). Dòng thứ 2
chứa N số nguyên a1, a2, …. aN (ai<=109)
Kết quả: Ghi ra file văn bản SUBARR.OUT: Ghi ra số lượng dãy con tìm
được.
(Các số trên cùng một dòng của file dữ liệu vào ghi các nhau ít nhất một ký tự
trống)
Ví dụ:
SUBARR.INP
SUBARR.OUT
42
3
1212
*Code tham khảo:
Var A:Array[1..400000] of longint; D:Array[1..1000000000] of word;
sl:int64;i,j,n,k:longint; f,g:text;
Procedure XuLy;
Begin
i:=1;j:=0;
while (i<=n-k+1)and(j<=n) do
Begin
if D[A[j]]Begin
j:=j+1;
D[A[j]]:=D[A[j]]+1;

End
Else Begin
sl:=sl+1+N-j;
D[A[i]]:=D[A[i]]-1;
i:=i+1;
End;End;End;
Begin
assign(f,'SUBARR.INP',); reset(f);
assign(g, 'SUBARR.OUT'); rewrite(g);
11


readln(f,n,k);
for i:= 1 to N do
read(f,A[i]);
XuLy;
write(g,sl);
close(g);close(f);
End.
*Một số bài tập cơ bản
1.
2.

3.
4.
5.

6.
7.


Dãy con dương liên tiếp có nhiều các số hạng nhất (nếu có nhiều dãy con
thoả mãn thì đọc ra màn hình: Số dãy con thoả mãn và các dãy con đó).
Dãy con có các số hạng dương liên tiếp có tổng lớn nhất (nếu có nhiều
dãy con thoả mãn thì đọc ra màn hình: Số dãy con thoả mãn và các dãy
con đó).
Dãy con có các số hạng âm liên tiếp nhiều nhất (nếu có nhiều dãy con
thoả mãn thì đọc ra màn hình: Số dãy con thoả mãn và các dãy con đó).
Dãy con có số hạng âm liên tiếp có tổng lớn nhất (nếu có nhiều dãy con
thoả mãn thì đọc ra màn hình: Số dãy con thoả mãn và các dãy con đó).
Dãy con có các số hạng liên tiếp đan dấu nhiều nhất (nếu có nhiều dãy
con thoả mãn thì đọc ra màn hình: Số dãy con thoả mãn và các dãy con
đó).
Dãy con có các phần tử khơng tăng nhiều nhất (nếu có nhiều dãy con thoả
mãn thì đọc ra màn hình: Số dãy con thoả mãn và các dãy con đó).
Dãy con có các phần tử giảm nhiều nhất(nếu có nhiều dãy con thoả mãn
thì đọc ra màn hình: Số dãy con thoả mãn và các dãy con đó).

2.3.3.2 Dãy con có thể chung nhau phần tử của dãy mẹ
Các dãy con có thể chung nhau phần tử của dãy mẹ nghĩa là những phần
tử của dãy mẹ đã thuộc dãy con thỏa mãn này thì vẫn có thể thuộc hoặc khơng
thuộc các dãy con thỏa mãn khác.
Ví dụ: Dãy mẹ gồm 7 phần tử {1,2,3,6,9,-6,8}. Dãy con {1,2,3}; {1,2,3,6};{6,8} là các dãy con có thể chung nhau phần tử của dãy mẹ.
Bài toán cơ bản
Cho một dãy A gồm N số nguyên (a1, a2,…, An). Dãy con ai, ai+1,…,
aj(1≤i≤j≤N) là dãy được tạo từ các phần tử liên tiếp của dãy A bắt đầu từ phần tử
i và kết thúc ở phần tử j. Tìm các dãy con thỏa mãn một điều kiện nào đó.
Để giải dạng bài tập này ta có thể sử dụng thuật toán vét cạn các dãy con hoặc
sử dụng phương pháp quy hoạch động. Đối với dạng bài tập này tôi định hướng
cho học sinh lựa chọn thuật toán quy hoạch động.
*Thuật toán:

- Gọi f[i] là giá trị dãy con (tùy điều kiện bài toán) từ phần tử thứ 1 đến phần tử
thứ i
- Lập công thức tính giá trị dãy con từ i đến j theo f[i] và f[j].
12


- Xét tất cả các cặp số (i,j) bằng hai vòng lặp sau:
for i:= 1 to n-1 do
for j:= i to n do
begin
{Xét các dãy con từ phần tử i đến j thỏa mãn điều kiện thì tăng số dãy, lưu chỉ
số đầu, chỉ số cuối}
end;
Bài toán 1:
Cho một dãy A gồm N số nguyên (a1, a2,…, An). Dãy con ai, ai+1,..,
aj(1≤i≤j≤N) là dãy được tạo từ các phần tử liên tiếp của dãy A bắt đầu từ phần tử
i và kết thúc ở phần tử j.
Yêu cầu: Hãy tìm dãy con liên tiếp có tổng lớn nhất.
Dữ liệu vào: File văn bản Tong.inp gồm:
- Dòng đầu ghi giá trị N (1≤N≤10000).
- Dòng sau gồm N số nguyên (a1, a2,…, An) (-106≤ai≤106) mỗi số cách
nhau một dấu cách.
Dữ liệu ra: File văn bản Tong.out gồm
- Dòng đầu ghi tổng các phần tử dãy con và số lượng dãy con.
- Dòng tiếp theo ghi giá trị các phần tử dãy con.
Ví dụ:
Tong.inp

Tong.out


13
52 2
12 -34 14 11 9 -8 15 11 -7 -56 17 16 14 11 9 -8 15 11
19
17 16 19
Cách 1:Với bài toán này, cách đầu tiên học sinh lựa chọn là vét cạn.
*Thuật toán:
For i:=1 to n do
For j:=1 to n-i+1 do
Begin
{Xét tất cả các dãy con bắt đầu từ vị trí i có độ dài j}
end;
hoặc For k:=1 to n do
For j:=1 to n-k+1 do
begin
j:=i+k-1;
{Xét tất cả các dãy con bắt đầu từ vị trí i đến vị trí j với độ dài k}
end;
Cách 2: Sử dụng phương pháp quy hoạch động.
*Thuật toán:
-Gọi f[i] là tổng tất cả các phần tử từ 1 đến i.
-Như vậy dãy con liên tiếp từ i đến j có tổng là: f[j]-f[i-1].
-Xét tất cả các dãy con từ i đến j bằng 2 vòng lặp:
13


for i:= 1 to n-1 do
for j:= i to n do
begin
{Xét f[j]-f[i-1] thỏa mãn điều kiện thì tăng số dãy, lưu chỉ số đầu, chỉ số cuối}

end;
*Code tham khảo:
Var a,f,dau,cuoi:array[0..100001] of longint; s,g:text;
i,j,n,dem:longint;tmax,k:int64;
Begin
assign(s, 'tong.inp');reset(s);assign(g, 'tong.out');rewrite(g);
readln(s,n);for i:=1 to n do read(s,a[i]);
f[0]:=0;
for i:= 1 to n do f[i]:= f[i-1]+a[i];
tmax:= a[1];k:=0;
for i:= 1 to n-1 do
for j:= i to n do
begin
if f[j]- f[i-1] > tmax then begin tmax:= f[j] - f[i-1];k:=0;end;
if f[j]-f[i-1] =tmax then begin inc(k);dau[k]:=i;cuoi[k]:=j; end;
end;
writeln(g,tmax,' ',k);
for i:= 1 to k do
begin
for j:= dau[i] to cuoi[i] do write(g,a[j], ' '); writeln;
end;
close(s);close(g);
END.
Từ thuật toán dễ dàng nhận thấy ở cách 2 thuật toán ngắn gọn và tối ưu
hơn trong cách giải quyết bài tốn và tơi thường hướng dẫn, phân tích để các em
chọn cách 2.
Bài toán 2:
Cho một dãy A gồm N số nguyên (a1, a2,…, An) và một số nguyên K.
Dãy con ai, ai+1,…, aj (1≤i≤j≤N) là dãy được tạo từ các phần tử liên tiếp của
dãy A bắt đầu từ phần tử i và kết thúc ở phần tử j.

Yêu cầu: Hãy tìm dãy con liên tiếp có tổng các phần tử chia hết cho K.
Dữ liệu vào: File văn bản dayconchiahet.inp gồm:
- Dòng đầu ghi hai số nguyên N và M (1≤N≤10000 ; 1≤M≤1000 ).
- Dòng sau gồm N số nguyên (a1, a2,…, An) (-106≤ai≤106), ai<>0) mỗi số
cách nhau một dấu cách.
Dữ liệu ra: File văn bản dayconchiahet.out gồm
- Dòng đầu ghi số lượng dãy con thỏa mãn.
- Dòng tiếp theo ghi giá trị các phần tử dãy con thỏa mãn.
Ví dụ:
14


Dayconchiahet.inp

Dayconchiahet.out

43

2

1325

123
3

*Thuật toán:
- Gọi f[i] là tổng tất cả các phần tử từ 1 đến i.
- Như vậy dãy con liên tiếp từ i đến j có tổng là: f[j]-f[i-1].
- Xét tất cả các dãy con từ i đến j bằng 2 vòng lặp:
for i:= 1 to n-1 do

for j:= i to n do
begin
if (f[j]- f[i-1]) mod m =0 then
begin
inc(k);dau[k]:=i;cuoi[k]:=j;
end;{in ket qua}
2.3.3.3 Dãy con gồm các phần tử không liên tiếp.
Cho một dãy A gồm N số nguyên (a1, a2,…, An). Dãy con ai, ai+1,…,
aj(1≤i≤j≤N) là dãy thu được khi ta xóa một số phần tử (có thể khơng xóa phần tử
nào và khơng được xóa hết) của một dãy cho trước (dãy mẹ) và giữ nguyên thứ
tự các phần tử cịn lại trong dãy. Hãy tìm các dãy con thỏa mãn một điều kiện
nào đó.
Bài tốn thường sử dụng phương pháp quy hoạch động, phương pháp trục
số, vòng lặp lồng nhau, quay lui, đệ quy. Đối với dạng bài tập này tơi định
hướng cho học sinh lựa chọn thuật tốn quy hoạch động là tối ưu hơn cả.
*Thuật toán:
- Gán giá trị cho bài tốn cơ sở.
-Tính giá trị cho bài tốn thứ i nhờ các bài tốn đã tính trước đó.
-Kết quả bài tốn là sự tổng hợp từ các bài toán ban đầu.
Bài toán 1: Dãy con đơn điệu tăng
Cho một dãy số nguyên gồm N phần tử a1, a2, a3, …, aN. Biết rằng dãy
con tăng đơn điệu là 1 dãy a[i1], a[i2], …, a[ik] thỏa mãn:
+ i1< i2 < … < ik;
+ a[i1] < a[i2] < a[i3] < … < a[ik].
Yêu cầu: Hãy cho biết dãy con tăng đơn điệu dài nhất của dãy này có bao nhiêu
phần tử?
Dữ liệu: Vào từ file văn bản BAI1.INP
- Dòng 1: ghi số N (0 < N ≤ 1000);
15



- Dòng 2: ghi N số a1, a2, …, aN đơi một khác nhau và cách nhau ít nhất một
dấu cách ( |ai| ≤ 10000).
Kết quả: Ghi ra file văn bản BAI1.OUT
Chỉ gồm một dòng ghi độ dài dãy con tăng đơn điệu dài nhất.
Ví dụ:
Bai1.inp
6
125473

Bai1.out
4

*Thuật tốn:
Với cách làm này ta đã chia 1 bài toán lớn (dãy con của n số) thành các
bài tốn con cùng kiểu có kích thước nhỏ hơn (dãy con của dãy i số).
-Gọi L(i) là độ dài dãy con tăng dài nhất, các phần tử lấy trong miền từ a1
đến ai và phần tử cuối cùng là ai. Dãy con đơn điệu tăng dài nhất kết thúc tại ai
sẽ được thành lập bằng cách.
-Kiểm tra xem có bao nhiêu dãy con đơn điệu tăng (các phần tử trong
miền từ a1 đến ai-1) mà ta có thể ghép ai vào cuối dãy đó;
-Chọn dãy con đơn điệu có độ dài lớn nhất để ghép ai vào.
-Ta có cơng thức quy hoạch động để tính L(i) như sau:
+ L(1) = 1 (Hiển nhiên);
+ L(i) = max(1, L(j)+1 với mọi phần tử j: 0 < j < i và aj < ai).
Tính L(i): phần tử đang được xét là ai. Ta tìm đến phần tử aj < ai có L(j) lớn
nhất. Khi đó nếu bổ sung ai vào sau dãy con a1... aj ta sẽ được dãy con tăng dần
dài nhất xét từ a1... ai.
*Code tham khảo:
var f1, f2: text;

a, f: array[1..1000] of integer;
h, i, j, n, max: integer;
tg, cs: string;
begin
assign(f1, 'BAI1.INP'); reset(f1);
assign(f2, 'BAI1.OUT'); rewrite(f2);
readln(f1, n);
for i:= 1 to n do read(f1, a[i]);
f[1]:= 1;
for i:= 2 to n do
begin
f[i]:= 1;
for j:= 1 to i-1 do
if (a[i] > a[j]) and (f[i] < f[j]+1) then f[i]:= f[j]+1;
if max < f[i] then max:= f[i];
end;
writeln(f2, max);
16


close(f1);close(f2);
end.
Bài toán 2 Chia đoạn một dãy số (Đề HSG tỉnh 2010-2011)
Cho dãy số tự nhiên a1, a2,..., an. Hãy tìm cách chia dãy số trên thành nhiều
đoạn nhất sao cho tổng các số trong tất cả các đoạn con đều bằng nhau.
Dữ liệu vào: từ file BAI4.INP gồm:
-Dòng đầu ghi số n.
-Các dòng còn lại ghi các số a1, a2,..., an.
Các số trên cùng một dịng cách nhau ít nhất một dấu cách trống.
Kết quả: ghi ra file BAI4.OUT, gồm K+1 dòng (K là số đoạn chia được nhiều

nhất) như sau:
-Dòng đầu ghi hai số K và S (S là tổng giá trị của một đoạn).
- K dòng còn lại mỗi dòng ghi các số của mỗi đoạn chia được.
Các số trên cùng một dịng cách nhau ít nhất một dấu cách trống.
Ví dụ:
BAI4.INP
6
351780

BAI4.OUT
38
35
17
80

*Code tham khảo:
var A, C : array[1..100] of word; n : word;
procedure doc;
var i : word; f : text;
begin
fillchar (a, sizeof(a), 0);
fillchar (c, sizeof(c), 0);
assign (f, 'bai4.inp' ); reset (f);
readln(f, n);
for i:=1 to n do
read(f, a[i]);close(f);
end;
function chiaduoc(tt, n, k : word) : boolean;
var t, s, i, m : word;
begin

chiaduoc := false;
t := tt div k;
if t*k <> tt then exit;
m:=1;c[m] := 0; s:=0;
for i:=1 to n do
begin
s:= s + a[i];
17


if s > t then exit;
if s = t then
begin
inc(m); c[m] := i; s := 0;
end; end;
c[m] := n;
chiaduoc:=true;
end;
procedure chianho(n : word);
var i, tt, k, j : word;g: text;
Begin
assign(g, 'bai4.out'); rewrite(g);
tt := 0;
for k:=1 to n do
tt := tt + a[k];
for k := n downto 1 do
if chiaduoc(tt, n, k) then
begin
writeln (g, k, ' ', tt div k);
if k = 1 then

for i:=1 to n do
write (g, a[i],' ')
else begin
for i := 1 to k do
begin
for j := c[i] + 1 to c[i+1] do
write (g, a[j],' '); writeln (g);
end;exit;
end; end; close(g); end;
BEGIN
doc;
chianho(n);
END.
Thời gian thực hiện giải pháp 3: Là 4 buổi ôn tập (mỗi buổi ôn một dạng và
một buổi làm bài tập tổng hợp). Mỗi buổi là 1 dạng riêng, giáo viên giới thiệu
bài toán, cho học sinh nêu ý tưởng và lập trình hồn chỉnh theo cách các em đưa
ra. Giáo viên dùng phần mềm chấm Themis để học sinh thấy kết quả từ đó nhận
xét đưa ra thuật toán tối ưu, chỉnh sửa code và chấm lại đề học sinh thấy được sự
khác biệt về điểm số trong từng thuật toán. Giúp học sinh nhận biết bài toán và
giải pháp tối ưu nhất cho từng bài cụ thể.
Kết quả sau khi thực hiện giải pháp 3: Với các bài lập trình liên quan tới
mảng 1 chiều, đặc biệt các bài toán về dãy con, học sinh nắm vững các thuật
toán, biết cách vận dụng, lựa chọn thuật tốn tối ưu cho từng bài cụ thể để có thể
đạt điểm cao.
18


2.4. Hiệu quả của sáng kiến.
Trong quá trình bồi dưỡng đội tuyển học sinh giỏi, tơi và nhóm giáo viên
phụ trách giảng dạy bộ môn Tin học của trường THPT Nguyễn Quán Nho đã áp

dụng sáng kiến này. Tôi nhận thấy sau khi áp dụng sáng kiến này, các em học
sinh trong đội tuyển học sinh giỏi giải quyết tốt hơn các dạng bài toán về dãy
con và dần khắc phục được lỗi mất điểm do sử dụng phương pháp chưa tối ưu
trong các bài thi.
Với bản thân tôi thấy việc “Một số giải pháp phân loại và tối ưu cho
các bài tốn về dãy con trong ơn luyện học sinh giỏi môn tin học” giúp cho
giáo viên dạy đội tuyển và học sinh có tài liệu cụ thể, dễ hiểu và kết quả thi học
sinh giỏi hằng năm cũng được cải thiện.
Một số kết quả học sinh giỏi tỉnh của trường tôi như sau:
Năm học 2016-2017, đạt 2 giải 3 (Đỗ Ngọc Tỉnh lớp 11B1 và Nguyễn Thị
Dương lớp 12C1). Môn Tin đạt kết quả cao nhất so với các trường trong huyện
Thiệu Hóa.
Năm học 2017 – 2018, đạt 2 giải khuyến khích (Nguyễn Quốc Dũng và Nguyễn
Trọng Thích lớp 11B3). Môn Tin đạt kết quả đứng thứ 2 so với các trường trong
huyện Thiệu Hóa.
Năm 2019-2020, đạt 1 giải khuyến khích (Nguyễn Hữu Đạt lớp 12C3). Mơn tin
đạt kết quả bằng với trường Thiệu Hóa, cao hơn Lê Văn Hưu (là 2 trường chất
lượng học sinh tốt trong huyện).
3. Kết luận và kiến nghị
3.1. Kết luận.
Đối với các học sinh khá, giỏi việc tạo cho các em niềm say mê và biết
cách suy nghĩ để lập trình một cách tối ưu ngay từ khi tiếp cận với bộ mơn Tin
học lập trình là việc làm quan trọng nhất của mỗi giáo viên. Có say mê và khả
năng lập trình tốt giúp các em học tập hiệu quả, đạt kết quả cao trong các kỳ thi
học sinh giỏi. Những vấn đề của Tin học lập trình chính là cách tư duy lôgic
khoa học, khả năng đánh giá vấn đề, phân loại là lựa chọn đúng thuật tốn.
Như vậy có thể kết luận về hiệu quả đạt được khi tôi và đồng nghiệp áp
dụng nội dung sáng kiến như sau: Học sinh dễ dàng hơn trong việc nhận dạng,
phân loại bài tập, hệ thống được kiến thức trong mảng 1 chiều và các bài tập liên
quan đến dãy con. Khả năng lập trình của các em được cải thiện, ln tìm cách

tối ưu thuật tốn để chương trình hồn thiện, chạy ít tốn thời gian nhất và lấy
được điểm cao dù gặp những bài test lớn.
Sau quá trình nghiên cứu tôi đã rút ra được nhiều kinh nghiệm thực tế
trong dạy học trên lớp và ôn luyện đội tuyển. Tôi cũng trao đổi phương pháp với
19


đồng nghiệp để áp dụng vào dạy học bộ môn. Tuy nhiên đề tài chỉ mới nghiên
cứu ở mảng nhỏ của kiến thức thi học sinh giỏi là dãy con rất mong được sự góp
ý của bạn bè và đồng nghiệp để đề tài được hoàn thiện và ứng dụng rộng rãi
hơn.
Trên đây là một số kinh nghiệm của bản thân sau một thời gian giảng dạy
bộ môn Tin học và ôn luyện đội tuyển thi học sinh giỏi tỉnh về ngơn ngữ lập
trình Pascal Trong khn khổ bài viết, với kinh nghiệm và vốn kiến thức có hạn
tơi rất mong được sự góp ý, trao đổi từ các đồng nghiệp.
3.2. Kiến nghị
Đối với giáo viên, phải không ngừng học hỏi nâng cao trình độ, tìm hiểu
những cái mới, tìm hiểu đối tượng học sinh để dạy học mang lại hiệu quả cao
nhất.
Đối với nhà trường, tăng cường cơ sở vật chất, đầu tư máy tính xách tay
cho đội tuyển phục vụ việc học và thi học sinh giỏi. Tạo điều kiện cho nhóm tin
lấy được nguồn học sinh giỏi có chất lượng, xếp lịch ơn luyện cho các đội tuyển
Đối với học sinh, cần có tinh thần tự giác, tự học, có ý thức học tập
nghiêm túc, giúp đỡ bạn bè cùng cố gắng.
Các bài tập trình bày trong sáng kiến do tôi sưu tầm, phân loại, tự thiết kế
giải thuật và cài đặt nên có thể cịn nhiều thiếu sót. Rất mong được sự góp ý
chân thành từ bạn bè đồng nghiệp để sáng kiến được hoàn thiện hơn và có thể
ứng dụng rộng rãi hơn.
Tơi xin chân thành cảm ơn!
Thanh Hóa, ngày 26 tháng 4 năm 2021

Xác nhận của hiệu trưởng.

Tôi xin cam đoan đây là SKKN của
mình viết, khơng sao chép nội dung
của người khác.
Người viết:

Hồng Thị Kim

20


Tài liệu tham khảo
[1]: />[2]: />[3] />[4] Tài liệu tập huấn giáo viên tin 2017 (nguồn nội bộ).
[5] Sách giáo khoa tin học 11.
[6] Nguồn youtube

21



×