Tải bản đầy đủ (.doc) (69 trang)

CÁC DẠNG BÀI VỀ DẠY CON VÀ HƯỚNG GIẢI QUYẾT

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 (450.78 KB, 69 trang )

SỞ GD - ĐT NAM ĐỊNH
TRƯỜNG THPT CHUYÊN LÊ HỒNG PHONG



SÁNG KIẾN DỰ THI CẤP TỈNH
BÁO CÁO SÁNG KIẾN:

CÁC DẠNG BÀI VỀ DÃY CON
VÀ HƯỚNG GIẢI QUYẾT

Tác giả: TRẦN THỊ THANH HUYỀN
Trình độ chuyên môn: Thạc sỹ Tin học
Chức vụ: Giáo viên
Nơi công tác: Trường THPT chuyên Lê Hồng Phong

Nam Định, 6/6-2015

Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

1


1. Tên sáng kiến: CÁC DẠNG BÀI VỀ DÃY CON VÀ HƯỚNG GIẢI QUYẾT
2. Lĩnh vực áp dụng: Giảng dạy trong môn Tin cho học sinh khối chuyên Tin, đội
tuyển HSG đồng bằng Bắc bộ khối 10, khối 11, bồi dưỡng đội tuyển HSG Quốc gia.
3. Thời gian áp dụng:
- Từ năm 2012 đến nay
4. Tác giả:
Họ tên : TRẦN THỊ THANH HUYỀN
Ngày sinh: 09-10-1978


Nơi thường trú: 2/24/131 TRẦN THÁI TÔNG- TP NAM ĐỊNH
Trình độ chuyên môn: Thạc sỹ Tin học
Chức vụ công tác: Giảng dạy bộ môn Tin học
Nơi làm việc: Trường THPT chuyên Lê Hồng Phong- Tp Nam Định
Địa chỉ: 76 Vị Xuyên
Điện thoại: 03503. 640.297
5. Đơn vị áp dụng sáng kiến
Tên đơn vị: Trường THPT chuyên Lê Hồng Phong- Tp Nam Định
Địa chỉ: 76 Vị Xuyên
Điện thoại: 03503. 640.297

Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

2


BÁO CÁO SÁNG KIẾN
I. ĐIỀU KIỆN HOÀN CẢNH TẠO RA SÁNG KIẾN
Một công việc quen thuộc của giáo viên khi giảng dạy Tin trong các lớp
chuyên đó là: bên cạnh việc thường xuyên phải hệ thống lại các dạng bài tập, lựa
chọn các dạng bài phù hợp để học sinh rèn kỹ năng cài đặt bài tập sau khi đã được
trang bị về lý thuyết thì một mục tiêu tối quan trọng là phân loại và phát hiện năng
khiếu về môn chuyên của học sinh.
Trong quá trình khai thác các dạng bài tập để dạy học và tự nghiên cứu, tôi gặp phải
rất nhiều dạng bài tập liên quan đến “dãy con” và nhận thấy chúng rất đa dạng và ở
nhiều mức độ khác nhau: từ dễ đến khó. Để giải quyết các bài toán về “dãy con” này
có thể phải vận dụng linh hoạt các chiến lược thiết kế 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. Đây cũng là những phương pháp
thiết kế thuật toán mà học sinh chuyên cần phải được rèn luyện nhiều khi làm bài

tập
II. MÔ TẢ GIẢI PHÁP
1. Mô tả giải pháp trước khi tạo ra sáng kiến
Trước đây, khi ôn tập cho học sinh chuyên Tin và dạy các đội tuyển, tôi đã
đưa ra một số bài tập nói trong tài liệu này song đưa ra một cách riêng lẻ, không có
hệ thống và theo từng chuyên đề thuật toán. Ví dụ: Đa số các bài về dãy con thường
có cách giải bằng phương pháp Quy hoạch động nên chúng có trong phần ví dụ áp
dụng của chuyên đề về Quy hoạch động. Tuy nhiên các bài toán về ”dãy con” rất đa
dạng, nhiều thể loại, có thể có nhiều phương pháp giải khác nhau. Vì vậy, tôi thiết
nghĩ: cần phải hệ thống hóa lại các bài tập liên quan đến xử lý “dãy con” và phân
loại chúng thành các dạng cụ thể để qua đó học sinh có thể rút ra được phương pháp
giải quyết phù hợp với từng dạng bài.
2.Mô tả giải pháp sau khi có sáng kiến

Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

3


Để góp phần giúp các em vận dụng linh hoạt và nhiều hơn nữa các phương pháp
thiết kế thuật toán vào giải các bài tập cụ thể, phổ biến như các dạng bài tập về dãy
con của học sinh chuyên tin cũng như góp phần xây dựng kho bài tập bồi dưỡng
HSG các cấp, trong tài liệu này tôi xin được trình bày vấn đề “ Các dạng bài toán
về dãy con và hướng giải quyết”

NỘI DUNG
A.Một số khái niệm
Cho một dãy N số nguyên A=(A1, A2, …, AN)
Ví dụ: A= (8 6 5 2 6 4 9) với N=7
+ Dãy con của một dãy A cho trước là một dãy thu được bằng cách xóa đi một số

phần tử của dãy A, các phần tử còn lại vẫn giữ đúng thứ tự. Mỗi dãy số là dãy con
của chính nó. Dãy rỗng là dãy con của mọi dãy bất kỳ.
Ví dụ: Dãy ( 6 5 4 9) là dãy con của A
+ Đoạn con (dãy đoạn con) của một dãy A cho trước là một dãy các phần tử liên
tiếp có trong A
Ví dụ: Dãy ( 6 5 2 6 ) là đoạn con của A
* Các kiến thức cần trang bị:
- Các thuật toán cơ bản: Tìm ước chung của 2 số, kiểm tra tính nguyên tố của một số
nguyên dương, kiểm tra tính nguyên tố cùng nhau của một cặp số, kiểm tra một số
thuộc dãy số Fibonacci,…
- Các thuật toán nâng cao: tìm kiếm nhị phân, sắp xếp nhanh, trộn mảng, thuật toán
sinh hoán vị, thuật toán loang, xử lý bit.
- Các phương pháp thiết kế thuật toán: duyệt-vét cạn, quay lui, quy hoạch động.

B. Các dạng bài tập
Dạng 1: Dãy con tăng dần (giảm dần) dài nhất (ngắn nhất)

Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

4


Bài 1. Đoạn con tăng dần dài nhất
Cho dãy gồm N số nguyên. Tìm đoạn con tăng dần có chiều dài lớn nhất.
Dữ liệu vào: tệp văn bản DAYCON.INP
Dòng thứ nhất: số tự nhiên N, 1 ≤ N ≤ 20000.
Từ dòng thứ hai trở đi: các phần tử của dãy.
Dữ liệu ra: tệp văn bản DAYCON.OUT

DAYCON.INP


DAYCON.OUT

Chứa một dòng duy nhất gồm hai số tự nhiên

12

47

d – chỉ số đầu đoạn và L – số phần tử trong

15513

đoạn (chiều dài đoạn).

33579

Trong các tệp, dữ liệu trên cùng dòng cách

12

nhau qua dấu cách.
Giải thích : Đó là dãy con 1 3 3 3 5 7 9
Thuật toán
- Ta đọc dần các phần tử từ input file và so sánh hai phần tử liên tiếp nhau là x
(phần tử đọc trước tại bước i) và y (phần tử đọc sau tại bước i+1).
- Nếu y < x thì coi như kết thúc một đoạn không giảm, ta cập nhật để ghi nhận lại
đoạn không giảm dài nhất.
Độ phức tạp: cỡ O(N).
Chương trình

program DAYCON;
uses crt;
const
fn = 'DAYCON.INP';
gn = 'DAYCON.OUT';
var f,g: text;
n: longint;
a: mw1;
iLeft, imax: longint;
MaxLen: longint;
procedure Update(i: longint);
begin

Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

5


if (MaxLen < i - iLeft) then
begin
MaxLen := i - iLeft;
imax := iLeft; ileft := i;
end;
iLeft := i;
end;
procedure XuLi;
var i, x, y: longint;
begin
assign(f,fn);


reset(f);

readln(f,n);

read(f,x);
iLeft := 1;

MaxLen := 0;

for i := 2 to n do
begin
read(f,y);
if (y < x) then Update(i);
x := y;
end;
Update(n+1);
close(f);
end;
procedure Ghi;
begin
assign(g,gn);

rewrite(g);

writeln(g,imax,’ ‘,MaxLen);
close(g);
end;
BEGIN
XuLi; ghi;
END.


Bài 2. Đoạn đơn điệu dài nhất
Cho dãy gồm N số nguyên. Tìm đoạn đơn điệu (không giảm hoặc không tăng)
có chiều dài lớn nhất.
Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

6


Dữ liệu vào: tệp DONDIEU.INP
Dòng thứ nhất: số tự nhiên N,
1≤N≤ 20000.
Từ dòng thứ hai trở đi: các phần tử của dãy.
Dữ liệu ra:tệp văn bản DONDIEU.OUT
DONDIEU.INP

Chứa một dòng duy nhất gồm hai số tự
nhiên d là chỉ số đầu đoạn và L là số

12

phần tử trong đoạn (chiều dài đoạn).

155133357912

DONDIEU.OUT
47

Thuật toán
Nhận xét:

Đoạn có 1 phần tử là đoạn đơn điệu (tăng, giảm),
Đoạn gồm một dãy liên tiếp các phần tử bằng nhau là đoạn đơn điệu (tăng, giảm).
Ta dùng hai biến đếm các phần tử tăng hoặc bằng nhau liên tiếp: dt và đếm các phần
tử giảm hoặc bằng nhau liên tiếp: dg.
- Nếu ai = ai−1 ta tăng đồng thời dt và dg 1 đơn vị. Nếu a i > ai−1 ta tăng dt thêm 1
đơn vị và đặt lại dg = 1.
- Nếu ai < ai−1 ta tăng dg thêm 1 đơn vị và chỉnh lại dt = 1. Sau mỗi bước ta cập
nhật đoạn đơn điệu dài nhất tìm được.
Độ phức tạp: cỡ O(N).
Chương trình
program DonDieu;
uses crt;
const
fn = 'DONDIEU.INP';
gn = 'DONDIEU.OUT';
var f,g: text;
n: longint;
dt,dg: longint;
iMax, MaxLen: longint;
function Max(a,b,c: longint): longint;
begin

Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

7


if (a < b) then a := b;
if (a > c) then Max := a
else Max := c;

end;
procedure XuLi;
var i,m,x,y: longint;
begin
assign(f,fn); reset(f);
readln(f,n); read(f,x);
dt := 1; dg := 1;
MaxLen := 1; iMax := 1;
for i := 2 to n do
begin
read(f,y);
if (y = x) then
begin

dt := dt + 1;

dg := dg + 1; end

else if (y > x) then
begin

dt := dt + 1;

else

begin

dg := 1;

end


dg := dg + 1;

dt := 1;

end;

MaxLen := m; iMax := i - MaxLen + 1;

end;

m := Max(MaxLen, dt, dg);
if (m > MaxLen) then
begin
x := y;
end;
close(f);
end;
procedure Ghi;
begin
assign(g,gn);

rewrite(g);

writeln(g, iMax,’ ‘, MaxLen);

close(g);

end;
BEGIN

XuLi; Ghi;
END.

Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

8


Bài 3. Chuỗi ốc
Biển Đà Nẵng được nhiều du khách biết đến như một trong những điểm nghỉ ngơi lý
tưởng và được tạp chí Forbes (Mỹ) bình chọn là một trong những bãi biển đẹp nhất
thế giới. Các bãi tắm có độ dốc lớn, nước trong xanh thích hợp cho những du khách
muốn thưởng thức các loại hình dịch vụ giải trí nghỉ dưỡng,
câu cá, lướt ván, lặn ngắm san hô, du thuyền,.. Trong một đợt đi du lịch ở Đà Nẵng,
sáng sớm DONG3D thường đi dạo dọc bờ biển và nhặt những vỏ ốc rồi xâu chúng
lại thành một chuỗi. Nguyên tắc tạo chuỗi ốc của DONG3D như sau: Ban đầu từ
chuỗi rỗng, không có vỏ ốc; khi gặp một vỏ ốc mới, có thể lấy để xâu vào một trong
hai đầu của chuỗi hoặc hoặc bỏ đi không lấy; cuối cùng nhận được một chuỗi vỏ ốc
mà tính từ đầu chuỗi đến cuối chuỗi, các vỏ ốc có kích thước tăng dần và gồm càng
nhiều vỏ ốc càng tốt.
Yêu cầu: Cho trước dãy a1, a2,…, an là kích thước của các vỏ ốc mà DONG3D lần
lượt gặp khi đi dọc bờ biển, hãy tìm cách nhặt và xâu chuỗi để được chuỗi gồm
nhiều vỏ ốc nhất.
Dữ liệu: Vào từ file BEADS.INP
Dòng 1 chứa số nguyên dương N ≤ 105

BEADS.INP BEADS.OUT
5

4


44531

Dòng 2 chứa N số nguyên dương a1, a2,…, an
(∀i: ai≤ 109) cách nhau bởi dấu cách.
Kết quả: Ghi ra file BEADS.OUT một số nguyên duy nhất là số lượng vỏ ốc trong
chuỗi tạo được.
Thuật toán:
- Tìm dãy con tăng dài nhất F[i] với i là phần tử đầu tiên
- Tìm dãy con giảm dài nhất F2[i] với i là phần tử đầu tiên
- Kết quả cần tìm của bài toán chính là max(F[i]+F2[i]-1);
Chương trình:
var fi,fo:text;
f,a,b,f2:array[1..100000]of longint;
i,n,max,tg,j:longint;
procedure day1;

Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

9


begin
f[n]:=1;
for i:=n-1 downto 1 do
begin
max:=0;
for j:=i+1 to n do
if (max<f[j])and(a[j]>a[i]) then max:=f[j];
f[i]:=max+1;

end;
end;
procedure day2;
begin
f2[n]:=1;
for i:=n-1 downto 1 do
begin
max:=0;
for j:=i+1 to n do
if (maxf2[i]:=max+1;
end;
end;
begin
assign(fi,'beads.inp');reset(fi);
assign(fo,'beads.out');rewrite(fo);
readln(fi,n);
for i:=1 to n do read(fi,a[i]);
day1;
day2;
max:=0;
for i:=1 to n do
if maxwrite(fo,max);
close(fi);close(fo);
end.

Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

10



Bài 4. Chỉnh dãy số
Cho một dãy N số nguyên dương không quá 109. Có thể giữ nguyên hoặc bỏ không
quá một đoạn liên tiếp các số trong dãy. Hãy thực hiện một trong hai cách trên sao
cho dãy số thu được có độ dài đoạn liên tiếp tăng dần là lớn nhất.
Ví dụ : - Với dãy 1 2 3 1 4 5 sẽ chỉ có cách bỏ số 1 thứ hai trong dãy đi để thu được
dãy mới có độ dài đoạn con liên tiếp tăng dần là 5
- Với dãy 1 3 4 6 ta không cần bỏ số nào đi
Dữ liệu vào từ file CDS.INP
- Dòng 1 : số nguyên T≤25 là số bộ

CDS.INP

CDS.OUT

test

2

4

- T nhóm dòng sau: mỗi nhóm gồm 2

9

6

dòng. Dòng đầu ghi số nguyên N,


534928671

dòng sau ghi N số nguyên là các số

7

trong dãy theo thứ tự từ trái qua phải

1 2 3 10 4 5 6

Kết quả ghi ra flie CDS.OUT chứa độ dài đoạn con liên tiếp tăng dần lớn nhất có
thể thu được.
Thuật toán :
Gọi L[i] là độ dài dãy dài nhất các số liên tiếp tăng dần kết thúc tại A[i]
R[i] là độ dài dãy dài nhất các số liên tiếp tăng dần bắt đầu tại A[i]
R và L tính được nhờ thuật toán quy hoạch động. Ta phải tìm giá trị cực đại của tổng
L[i]+R[j] sao cho i ≤ j và A[i]Xét hàm Find(L,R) để tìm giá trị Max của L[i]+R[j] với A[i]Ta chia đoạn [L,R] thành hai đoạn con [L,m] và [m+1,R] với m=(L+R) div 2.
Xét trường hợp :
+ Nếu i và j cùng thuộc một trong hai đoạn con này, giá trị max của L[i]+R[j] có thể
tính được nhờ thủ tục find(L,m) và find(m+1,R).
+ Nếu i thuộc đoạn con thứ nhất và j thuộc đoạn con còn lại, ta áp dụng Merge sort
để sắp xếp lại các A trong đoạn từ [L,R] tăng dần sau mỗi lần gọi find(L,R).

Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

11



Từ đó với mỗi i∈[L,m] ta có thể tìm kiếm nhị phân ra j∈[m+1,R] tương ứng sao cho
A[j] nhỏ nhất lớn hơn A[i] và tìm ra được giá trị lớn nhất của tổng L[i]+R[i]
Chương trình :
Program

defense ;

Uses math ;
Const

nfi=’CDS.inp’ ;
nfo=’CDS.out’ ;
maxn=100010 ;

var

a,r,l,c,f,d : array[0..maxn] of longint ;

n,res,ntest :longint ;
fi,fo :text ;
procedure enter ;
var i : longint ;
begin
read(fi,n)
for i :=1 to n do read(fi,a[i]) ;
end ;
procedure find(x,y:longint) ;
var i,u,v,m :longint ;
begin
if (x=y) then exit ;

m:=(x+y) div 2 ;
find(x,m); find(m+1,y);
f[y]:=r[c[y]] ;
for i:=y- 1 downto m+1 do
f[i]:= max(r[c[i]], f[i+1]) ;
v:= m+1 ;
for i:=x to m do
Begin
While (vIf a[c[v]]>a[c[i]] then res:=max(res,l[c[i]]+f[v]) ;
End ;
//tron 2 doan da sap xep

Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

12


u:=x ; v:=m+1 ;
for i :=x to y do
if(v>y)or((v<=y)and(u<=m)and(a[c[u]])begin
d[i] :=c[u] ; inc(u) ; end
else

begin

d[i] :=c[v] ; inc(v) ; end ;
for i := x to y do


c[i] :=d[i] ;

end ;
procedure solve ;
var i:longint ;
begin
L[1]:=1;
For i :=2 to n do
begin
L[i] :=1
If (a[i]>a[i-1]) then l[i] :=l[i-1]+1 ;
End ;
R[n] :=1 ;
For i :=n-1 downto 1 do
begin
R[i] :=1 ;
If (a[i]End ;
Res :=1 ;
For i :=1 to n do c[i]=i
//sap xep c theo chieu tang dan cua a[c[i]]
//ket hop tinh gia tri cuc dai cua res
Find(1,n) ;
End ;
Begin
Assign(fi,nfi) ; reset(fi) ;
Assign(fo,nfo) ; rewrite(fo);
Readln(fi,ntest) ;

Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ


13


While ntest>0 do
begin
Dec(ntest);enter ;solve ;
Writeln(fo, res);
end ;
Close(fo) ; close(fi);
End.

Dạng 2 : Tổng, tích các phần tử của dãy con
Bài 5. Tổng đoạn ngắn nhất
Cho một dãy số nguyên a1, a2, a3, …, an. Tìm đoạn ngắn nhất các phần tử trong dãy
thỏa ai + ai + 1 + ai + 2 + … + aj = k.
Dữ liệu vào: tệp văn bản TDOAN.INP
Dòng thứ nhất: hai số tự nhiên N và K, 1 ≤ N ≤ 2000.
Từ dòng thứ hai trở đi: các phần tử của dãy.
Dữ liệu ra: tệp văn bản TDOAN.OUT
Chứa một dòng duy nhất gồm hai số tự nhiên d – chỉ số đầu đoạn và L – số
phần tử trong đoạn (chiều dài đoạn). Nếu vô nghiệm thì ghi 0 0.
Trong các tệp, dữ liệu trên cùng dòng cách nhau qua dấu cách.
TDOAN.INP

TDOAN.OUT

21 17

16 3


0 2 3 2 10 1 5 5 6 12 20 30 14 8 0 11 0 6 0 0 5
Xét

Thu
ật
toán
đoạn

a[i..j] với tồng S = a[i] + a[i+1] + … + a[j], i ≤ j. Ta cho đoạn này dịch dần sang phải
và xét ba tình huống sau đây.
+ S = K: ta ghi nhận điểm đầu i và độ dài đoạn là j−i+1. Nếu độ dài này nhỏ hơn độ
dài LMin thì ta cập nhật lại các giá trị iMin và Lmin (thủ tục Update). Rồi tiếp tục
xét đoạn con mới là a[i+1..j] .
+ S < K: Ta dịch từ j sang j+1, giữ nguyên đầu i (thủ tục Right).
Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

14


+ S > K: Dịch từ i thành i+1 (thủ tục Left).
Ta đặt phần tử a[n+1] = 0 làm lính canh.
Chương trình:
program TDoan;
uses crt;
const
mn = 2001;
fn = 'TDOAN.INP';
gn = 'TDOAN.OUT';
type mw1 = array[0..mn] of word;

var f,g: text;
n,k: word;
a: mw1;
iMin, LMin: word;
iLeft,iRight: word;
sum: word;
procedure Doc;
var i: word;
begin
assign(f,fn); reset(f); readln(f,n, k);
for i := 1 to n do read(f,a[i]);
close(f);
end;
procedure Left;
begin
sum := sum - a[iLeft]; iLeft := iLeft + 1;
if (iLeft > iRight) then
begin iRight := iLeft; sum := a[iLeft]; end;
end;
procedure Right;
begin

iRight := iRight + 1;

sum := sum + a[iRight]; end;

procedure Update;
begin
if (LMin > iRight - iLeft + 1) then


Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

15


begin iMin := iLeft; LMin := iRight - iLeft + 1; end;
Left;
end;
procedure XuLi;
begin
iLeft := 1; iRight := iLeft;
LMin := n + 1; sum := a[1];
repeat
if (sum = k) then Update
else if (sum < k) then Right
else { sum > k } Left;
until (iRight > n);
if (LMin = n+1) then LMin := 0;
end;
procedure Ghi;
begin
assign(g,gn); rewrite(g); writeln(g,iMin,’ ‘,LMin); close(g);
end;
BEGIN
Doc; XuLi; ghi;
END.

Bài 6. Dãy con dài nhất tổng chia hết cho k
Cho một dãy số nguyên gồm N phần tử a 1 , a2, ..., aN và một số nguyên k. Giả
thiết dãy cho luôn luôn tồn tại một dãy con có tổng các phần tử chia hết cho k.

Yêu cầu : Hãy tìm dãy con có nhiều phần tử nhất có tổng các phần tử chia hết cho k.
Dữ liệu vào: Ghi trong file text, tên file là CK.INP gồm 2 dòng:
- Dòng đầu ghi 2 số nguyên N và k ( 0- Dòng tiếp theo ghi N số nguyên ai (0Dữ liệu ra : Ghi ra file text, tên file là CK.INP , gồm:
- Dòng đầu ghi độ dài dãy con tìm được
- Dòng tiếp theo ghi các phần tử của dãy con
- Dòng cuối cùng ghi tổng các phần tử của dãy con đó

Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

16


CK.INP
10 17

CK.OUT
8

12 32 14 11 22 5 25 44 52 17

12 32 14 11 5 44 52 17
187

Thuật toán tương tự bài 5 (tình huống 1) ở trên
Bài 7. SUBSEQ
Cho dãy N số nguyên a1, a2, ..., aN và số nguyên dương K.
Yêu cầu: Tìm đoạn con liên tiếp không ít hơn K số nguyên trong dãy sao cho tổng
các số nguyên thuộc đoạn là lớn nhất.

Dữ liệu: Cho trong tệp SUBSEQ.INP, gồm có:
- Dòng đầu chứa hai số nguyên N và K, trong đó N là số lượng các số nguyên trong
dãy và K là số lượng tối thiểu các số nguyên liên tiếp của một đoạn con.
- N dòng tiếp theo, dòng i +1 chứa một số nguyên ai.
Kết quả: Ghi ra tệp SUBSEQ.OUT một số nguyên P, cho biết tổng các giá trị đoạn
con tìm được theo yêu cầu.
Hạn chế:
- 1 ≤ N ≤ 1 000 000 và 1 ≤ K ≤ N.
Ví dụ:
SUBSEQ.INP SUBSEQ.OUT
83
120
-20
90
-30
-20
80
-70
-60
125
Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

17


Thuật toán
Gọi a1, a2, ... , aN là các số nguyên trong dãy input. Nhiệm vụ của chúng ta là xác
định i, j với i ≤ j và j - i +1 ≥ K và S = ai + ai+1 ... + aj là lớn nhất.
+ Ý tưởng Duyệt toàn bộ: Lựa chọn mọi cặp (i, j), tính tổng dãy a i + ai+1+...+ aj và
chọn giá trị tối đa trong số các tổng này. Có C(N, 2) cặp cần xem xét, tính tổng của

một đoạn như vậy có thể mất N phép cộng. Thuật toán này có độ phức tạp O(N3).
+ Ý tưởng Quy hoạch động:
sum := 0;
for j := 1 to K do sum := sum + P[j];
S[K] := sum;

//s: sumK

B[K] := sum;

//B: bestK

Ans := sum;
for j := K+1 to
S[j] :=

N do begin
S[j-1] + P[j]

- P[j-K];

B[j] := Max(B[j-1] + P[j], S[j] );
if Ans < B[j] then Ans := B[j];
end;
Write(Ans);

Chương trình
program dayconmax;
const
maxn=1000000;

fi='subseq.inp';
fo='subseq.out';
var p : array[1..maxn]of longint;
b, s : array[1..maxn]of longint;
n, k, ans, sum : longint;
f : text;
procedure nhapdl;
var i : longint;
begin
assign(f,fi); reset(f);

Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

18


readln(f,n,k);
for i := 1 to n do readln(f,p[i]);
close(f);
end;
function max (x, y: longint): longint;
begin
max := x;
if x < y then max := y;
end;
procedure tinh;
var j : longint;
begin
sum := 0;
for j := 1 to k do sum := sum + p[j];

S[K] := sum;
B[K] := sum;
Ans := sum;
for j := K+1 to N do begin
S[j] :=

S[j-1] + P[j]

- P[j-K];

B[j] := Max( B[j-1] + P[j], S[j] );
if (Ans < B[j]) then Ans := B[j];
end;
end;
begin
nhapdl;
tinh;
assign(f, fo); rewrite(f); write(f, ans); close(f);
end.

Bài 8. DÃY SỐ
Cho 1 dãy số gồm N phần tử (N ≤ 10000), mỗi phần tử có 1 giá trị nằm trong
khoảng [-1000, 1000]. Ban đầu, bạn sẽ ở vị trí ô số 0 với tổng điểm là 0. Mỗi nước
đi, người chơi có thể di chuyển sang phải tối thiểu là 1 bước và tối đa là K bước (K
Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

19


≤10) . Khi dừng lại ở 1 ô nào đó thì giá trị của ô đó sẽ được cộng vào tổng điểm.

Bạn có thể dừng cuộc chơi bất cứ lúc nào. Hãy tìm cách chơi sao cho tổng điểm
nhận được là nhiều nhất.
Dữ liệu : vào từ file AMMSEQ.INP
- Dòng đầu tiên chứa 2 số N, K. Với N ≤ 10000; K ≤ 10.
- Dòng thứ 2 chứa N số của dãy, mỗi số cách

AMMSEQ.INP AMMSEQ.OUT

nhau 1 dấu cách. Mỗi số nằm trong khoảng [-

52

1000, 1000]

-2 3 -6 -4 5

4

Kết quả: Ghi ra file AMMSEQ.OUT
Gồm một dòng duy nhất là Số điểm lớn nhất có thể đạt được.
Giải thích:
- Ta có thể đi theo thứ tự 0 -> 2 -> 4 -> 5. Số điểm đạt được là 0 + 3 – 4 + 5 = 4.
Thuật toán:
- Sử dụng phương pháp Quy hoạch động.
- Gọi F[i] là giá trị lớn nhất đạt được khi đến vị trí i.
Khởi tạo: F[1]=max(0,a[1]);
Ta có công thức tổng quát F[i]=max(F[i], F[i-j]+a[i]) với i:2 n, j: 1k
- Kết quả là Max(F[i])
Chương trình
uses math;

var
a,f:array[1..1000001] of longint;
i,n,kq,j,k:longint;
begin
readln(n,k);
for i:=1 to n do

Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

20


begin
f[i]:=-10000;
read(a[i]);
end;
f[1]:=max(0,a[1]);
for i:=2 to n do
begin
for j:=1 to k do
f[i]:=max(f[i],f[i-j]+a[i]);
if kq < f[i]then kq:=f[i];
end;
writeln(kq);
end.

Bài 9. Tích lớn nhất
Cho dãy N số nguyên a1, a2, ..., aN
Yêu cầu: Hãy tìm ra k số nguyên trong dãy sao cho tích các số nguyên đó là lớn
nhất

Dữ liệu: Cho trong tệp TLN.INP, gồm có:
- Dòng đầu chứa hai số nguyên N và K, trong đó N là số lượng các số nguyên trong
dãy và K là số lượng các số nguyên thỏa đầu bài.
- dòng tiếp theo chứa N số nguyên ai.

TLN.INP
53

Kết quả: Ghi ra tệp TLN.OUT k số nguyên tìm

1 5 -8 -5 -9

TLN.OUT
-8 -9 5

được theo yêu cầu.
Thuật toán:
- Sắp xếp giá trị tuyệt đối của các số theo thứ tự lớn đến bé
- Xét thấy nếu có 2 số âm thì cho 2 số âm đó thành dương.
- In ra k số lớn nhất
Chương trình
Var

fa,fz:text;
n,m,j,i,k:longint;
a,b:array[0..10000]of longint;

Begin

Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ


21


assign(fa,'TLN.inp'); reset(fa);
assign(fz,'TLN.out'); rewrite(fz);
Readln(fa,n,k);
for i:=1 to n do

read(fa,a[i]);

b:=a;
for i:=1 to n-1 do
for j:=i+1 to n do
if abs(a[i])Begin
m:=a[i];
a[i]:=a[j];
a[j]:=m;
end;
b:=a;
for i:=1 to n-1 do
if a[i]<0 then
for j:=i+1 to n do
if a[j]<0 then
begin
a[j]:=abs(a[j]);
a[i]:=abs(a[i]);
break;
end;

for i:=1 to n-1 do
for j:=i+1 to n do
if (a[i])<(a[j]) then
Begin
m:=a[i]; a[i]:=a[j];a[j]:=m;
m:=b[i]; b[i]:=b[j];b[j]:=m;
end;
for i:=1 to k do write(fz,b[i],' ');
Close(fa);
close(fz);
End.

Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

22


Bài 10. Trò chơi băng số
Trò chơi với băng số là trò chơi tham gia trúng thưởng được mô tả như sau: Có một
băng hình chữ nhật được chia ra làm n ô vuông, đánh số từ trái qua phải bắt đầu từ 1.
Trên ô vuông thứ i người ta ghi một số nguyên dương ai, i = 1, 2, ..., n. Ở một lượt
chơi, người tham gia trò chơi được quyền lựa chọn một số lượng tùy ý các ô trên
băng số. Giả sử theo thứ tự từ trái qua phải, người chơi lựa chọn các ô i1, i2, ..., ik.
Khi đó điểm số mà người chơi đạt được sẽ là:


ai1 - ai2 + ... + (-1)k-1aik

Yêu cầu: Hãy tính số điểm lớn nhất có thể đạt được từ một lượt chơi.
Dữ liệu:BANGSO.INP



Dòng đầu tiên chứa số nguyên dương n ( n ≤ 106 ) là số lượng ô của băng số;



Dòng thứ hai chứa n số nguyên dương a1, a2, ..., an ( ai ≤ 104, i = 1, 2, ..., n )
ghi trên băng số. Các số liên tiếp trên cùng dòng được ghi cách nhau bởi ít
nhất một dấu cách.

Kết quả: BANGSO.OUT


BANGSO.INP BANGSO.OUT
7
17
4924137

Một số nguyên duy nhất là số điểm lớn nhất có thể đạt được từ một lượt chơi.

Giải thích ví dụ: các số được chọn là 9, 2, 4, 1, 7 và 9-2+4-1+7=17

Thuật toán:
Ta sẽ dùng 2 mảng quy hoạch động
Gọi F[i] là giá trị lớn nhất khi xét tới số thứ i, và có thể đặt dấu + trước số đó
Gọi G[i] là giá trị lớn nhất khi xét tới số thứ i, và có thể đặt dấu - trước số đó
Ta có F[i] = max(F[i-1], G[i-1] + a[i]);
G[i] = max(G[i-1], F[i-1] - a[i]) với i:1n
Kết quả bài toán chính là max(f[n],g[n]);
Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ


23


Chương trình
uses math;
var f,g:array[1..1000000] of Int64;
a,n,i:longint;
fi,fo:text;
begin
assign(fi,'BANGSO.INP');

reset(fi);

assign(fo,'BANGSO.OUT');

rewrite(fo);

readln(fi,n);
for i:=1 to n do
begin
read(fi,a);
if i=1 then
begin
f[1]:=a;
g[1]:=0;
end
else
begin
f[i]:=max(g[i-1]+a,f[i-1]);

g[i]:=max(f[i-1]-a,g[i-1]);
end;
end;
writeln(fo,max(f[n],g[n]));
end.

Dạng 3: Dãy con có nhiều phần tử nhất mà các phần tử trong dãy thỏa một
tính chất nào đó
Bài 11. Dãy con Fibonacci
Cho một dãy các số nguyên a[1], a[2], ..., a[N] (N ≤ 1000). Hãy tìm trong dãy trên
một đoạn con tạo thành dãy Fibonacci dài nhất.
Dữ liệu vào: Cho trong file văn bản DAYF.INP có cấu trúc:
Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

24


- Dòng đầu chứa số N.
- Dòng thứ hai chứa N số nguyên a[i], mỗi số cách nhau một dấu cách (-30000 ≤
a[i] ≤ 30000).
Dữ liệu ra: Kết quả ghi vào file DAYF.OUT, gồm duy nhất một dòng là dãy
Fibonacci tìm được.
Ví dụ:
DAYF.INP
20

DAYF.OUT
1 1 2 3 5 8 13

1 2 7 4 1 1 2 3 6 7 1 1 2 3 5 8 13 9 10 20


Thuật toán:
- Sử dụng phương pháp duyệt toàn bộ
- Xây dựng chương trình con kiểm tra một dãy đảm bảo tính chất là dãy Fibonacci,
nghĩa là nếu một dãy d có y phần tử thì dãy đó có đặc điểm :
d[1]=1; d[2]=1; d[k]+d[k+1]=d[k+2] với k:3y-2
- Tìm tất các dãy con thỏa tính chất dãy Fibonacci, xác định độ dài của dãy con
thông qua cách lưu chỉ số của phần tử đầu và cuối của dãy con đó
- So sánh các độ dài này để tìm ra dãy con Fibonacci dài nhất
Chương trình:
type km=array[1..1000] of longint;
var
f,g:text;
i,n,j,max,c,d:longint;
a:km;
function fibo(d:km;x,y:longint):boolean;
var kt:boolean; k:longint;
begin
kt:=true;
for k:=x to y-2 do
if d[k]+d[k+1]<>d[k+2] then begin kt:=false;
break;
end;

Trần Thị Thanh Huyền - GV Trường THPT chuyên Lê Hồng Phong NĐ

25



×