toán nào mà ch ỉ sử dụng trong phạm vi Pascal để giải quyết mọi trường hợp bài toán đặt. ra hay không[r]
(1)SỞ GD& ĐT NGHỆ AN ĐỀ THI CHỌN HỌC SINH GIỎI TỈNH LỚP 11 NĂM HỌC 2013-2014
(Đề gồm trang)
Môn thi: TIN HỌC – THPT BẢNG A
Thời gian: 150 phút(không kể thời gian giao đề)
Bài Tên file nguồn File Input File Outout Thời gian chạy Điểm
Bài THANHGO.PAS THANHGO.INP THANHGO.OUT giây
Bài MIN.PAS MIN.INP MIN,OUT giây
Bài SDD.PAS SDD.INP SDD.OUT giây
Baì SUBARR.PAS SUBARR.INP SUBARR.OUT giây
Bài (5 điểm)
THANH GỖ
Cha Pinocchio muốn làm lại cho Picochio mũi Ơng có N gỗ,
thanh gỗ i có độ dài Là người yêu thích tốn học ơng ta đưa giải thuật sau để
lấy gỗ có độ dài cần thiết:
- Nếu lại gỗ ơng ta lấy gỗnày làm mũi cho Pinocchio - Nếu cịn nhiều gỗ ông ta làm sau:
Bước 1: Chọn gỗ i có độ dài nhỏ nhất, chọn gỗ j có độ
dài ajnhỏ lại
Bước 2: Nếu ai= ajthì vứt bỏ bớt thanh, quay Bước
Bước 3: Nếu ai< ajthì cắt khỏi ajđi đoạn ai, quay lại Bước u cầu:Hãytính độ dài gỗ mà ơng ta nhận để làm mũi cho Pinocchio
Giới hạn:1<=N <=10.000; 1<=ai<=109
Dữ liệu: Vào từ file văn THANHGO.INP: Dòng số N, dòng sau N số a1, a2, …., an
Kết quả: Ghi file văn THANHGO.OUT:Số X độ dài gỗ tìm
(Các số dịng file liệu vào cách ký tự trống) Ví dụ
THANHGO.INP THANHGO.OUT
3
1
Bài (6 điểm)
SỐ NHỎ NHẤT
Cho số nguyên dương K xâu ký tự S Xâu S gồm ký tự chữ
cái la tinh thường ‘a’… ‘z’ chữ số ‘0’… ‘9’, có K ký tự chữ số
Bạn viết chương gtrình loại bỏ số ký tự khỏi xâu S cho K ký tự
lại theo thứ tự tạo nên số nhỏ Trong K ký tự cịn lại cho phép
chữ số đứng đầu
Dữ liệu vào: Vào từ file văn MIN.INP: Dòng thứ số nguyên dương K
(K<=10) Dòng thứ hai ghi xâu S có độ dài nhỏ 250
Kết quả: Ghi file văn MIN.OUT: Gồm dòng ghi K ký tự lại tạo
nên số nhỏ
(2)Ví dụ:
MIN.INP MIN.OUT
4
307uv5xly08mnp 0108
Bài (5 điểm)
SỐ ĐƠN ĐIỆU
Số a1, a2, … , an gọi số đơn điệu < ai+1 > ai+2 hoặcai > ai+1 < ai+2 (Với
mọi i = n-2) Số có chữ số; số có hai chữ số khác gọi số đơn điệu có độ dài 1;
Ví dụ: số 5, 58, 3748, 32435465768 số đơn điệu vì: Số có chữ số
Số 58 có chữ số khác
Số 3748 có 3<7>4<8
Số 32435465768 ta thấy: 3>2<4>3<5>4<6>5<7>6<8
Yêu cầu:Viết chương trình xác định số chữ số lớn tạo thành số đơn điệu
một số cho trước
Dữ liệu: Vào từ file văn SDD.INP: Gồm số nguyên dương N có khơng q
75 số
Kết quả: Ghi file văn SDD.OUT: Chứa số nguyên số chữ số lơn tạo
thành số đơn điệu số N Ví dụ:
SDD.INP SDD.OUT
3748
Bài (4 điểm)
SUBARRAY
Cho dãy số nguyên a1, a2, … aN số nguyên dương K Dãy ai, ai+1, … aj
(1<=i<=j<=N) dãy đượctạo từ phần tử liên tiếp dãy A, phần tử i kết thúc phần từ j
Yêu cầu:Tìm số lượng dãy A có K phần tử Dữ liệu:Vào từ file văn SUBARR.INP:
Dòng cứa số nguyên dương N, K (1<=k<=N<=4.105) Dòng thứ chứa N
số nguyên a1, a2, … aN(ai<=109)
Kết quả:Ghi file văn SUBARR.OUT: Ghi số lượng dãy tìm
(Các số dịng file liệu vào ghi ký tự
trống) Ví dụ:
SUBARR.INP SUBARR.OUT
4 2
3
-
(3)HƯỚNG DẪN GIẢI
(Hướng dẫn mức độ người giải, nên hồn tồn khơng phải đáp án Vì có thể có nhiều lỗi khơng thể lấy 100% điểm tối đa đề ) Bài 1.
- Về liệu:
+ Có N gỗ N<=10.000 Cần màng 10.000 phầntử
+ Các Ai<=109 phải sử dụng kiểu Longint, longint chiếm byte
Nên tổng nhớ chiếm toàn là: 10.000 x = 40.000byte đáp ứng đủ - Về thuật tốn:
+ Nếu cịn lấy làm Mũi
+ Nếu ta thực bước
Bước 1: Chọn Ai nhỏ thanh, chọn Aj nhỏ thứ 2(chọn
nhỏ nhất)
Bước 2: Nếu Ai = Ajthì bỏ quay Bước (Bỏ Ai) Bước 3: Nếu Ai<Ajthì lấy Aj= Aj- Airồi quay Bước
Ta nhận thấy: Nếu bước chọn phần tử nhỏ nhất, sau Bước phần tử
là nhỏ nhất.Vì ta nhận thấy Bước tạo nên thuật tốn Tìm UCLN số nhỏ
nhất dãy Khi tìm ước chung số nhỏ lấy ước số nhỏ
tiếp theo để tìm UCLNBài tốn trở thành tốn: TÌM ƯỚC CHUNG LỚN
NHẤT CỦA dãy số
Như mặt kết ta tìm CULN được, chẳng cần phải từ từ tìm số nhỏ
nhất Nhưng liệu nhỏ nên code có phần xếp ý đồ yêu cầu bước thuật toán
Program THANHGO;
const fi='THANHGO.INP o='THANHGO.OUT Var a:array[1 10000] of longint; i,j,l,n:longint;
Procedure DocDL;
Begin
assign(input,fi); reset(input); readln(n);
for i:=1 to n read(A[i]); close(input);
End;
Procedure SapXep;
var tg,csm:longint; Begin
for i:=1 to n -1 Begin
csm:=i;
for j:= i+1 to n
(4)Begin tg:=A[i]; A[i]:=A[csm]; A[csm]:=tg End;
End; End;
Function Cat(a,b:integer):integer;
{thực tế hàm UCLNnhưng thay sử dụng phép Trừ sử dụng phép Chi cho nhanh}
Begin
while (a<>0) and (b<>0) if a>b then a:=a mod b else b:=b mod a; if a<>0 then Cat:=a else Cat:=b; End;
Procedure Xuly;
Begin
for i:=1 to n-1
A[i+1]:=Cat(A[i],A[i+1]); End;
Procedure LuuKQ;
Begin
assign(output,fo); rewrite(output); write(A[n]);
close(output); End;
Begin
DocDL; XuLy; LuuKq;
End. Bài 2:
- Về mặt liệu:Bài yêu cầu liệu xâu có độ dài khơng q 250 phần tử Nó xâu bình thường Pascal
+ K <=10 nên số nhỏ có tối đa 10 chữ số (longint đủ)
+Số nhỏ chứa số đầuSố nhỏ số cần xử lý phần chữ
số đứng đầu Đơn giản ta để XÂU(khi để xâu K khơng cịn quan trọng nữa)
- Về thuật tốn (u cầu): Tìm số nhỏ lấy từ xâu S
+ Rõ ràng ta cần tách ramột xâu gồm ký tự chữ Số riêng (không tách điều kiện
(5)+ Ta cần tìm K phần tử xâu chử số: Mỗi phần tử số nhỏ có
dãy xét:
Chú ý: Khi ta chọn phần tử thứ ithì ta phải dành cho K – i phần tử cuối cho phần tử Tức K = 10 ta chọn chữ số cho vị trí thứ ta phải
dành 10-1=9 chữ số cuối cho chữ số lại
function Min(i,j:byte):byte;
var csm:byte; Begin
csm:=i;
for i:=i+1 to j if S[csm]>S[i] then csm:=i;
Min:=csm;
Hàm trả vị tríký tự nhỏ xâu S kể từ vị trí I đến vị trí J Khi tìm chữ số i=1
Khi tìm vị trí chữ số xnào đóthì i bắt đầu tính từ i trước cộng với Thuật tốn đầy đủ là:
Program MIN;
const fi='MIN.INP'; fo='MIN.OUT'; Var S,s1:string;
i,l,j,k:byte;
Procedure DocDL;
Begin
assign(input,fi); reset(input); readln(k);
readln(s); close(input); End;
Function Loc(S:string):string;
var i:byte; tam:string; Begin
tam:='';
for i:=1 to length(s)
if('0'<=S[i]) and (S[i]<='9') then tam:=tam+S[i];
Loc:=tam; End;
function Min(i,j:byte):byte;
var csm:byte; Begin
csm:=i;
(6)if S[csm]>S[i] then csm:=i;
Min:=csm; End;
Procedure Xuly;
Begin
s:=Loc(s); l:=length(s); s1:='';
i:=0;
for j:=1 to k Begin
i:=Min(i+1,l-k+j); s1:= s1+ S[i] End;
End;
Procedure LuuKQ;
Begin
assign(output,fo); rewrite(output); write(s1);
close(output); End;
Begin
DocDL; XuLy; LuuKq;
End. Bài 3:
- Về mặt liệu: Số xét có tối đa 75 chữ số, điều kiện đơn điệu xét cho chữ số dãy số Dãy chữ số Số LỚN Vì ta nên sử dụng Xâu để lưu số lớn - Về mặt thuật toán: Bài giống dạng tìm đoạn đơn điệu tăng/giảm dài dãy số Thông thường gặp dạng ta sữ dụng số để lưuvị trí Đầu
tiên Kết thúc dãy dãy đơn điệu độ dài dãy đơn điệu dài Kết thúc dãy bắt đầu dãy
Thuật toán
Program SODD;
const fi='SDD.INP'; fo='SDD.OUT'; Var A:string;
d:byte;
Procedure DocDL;
Begin
(7)close(input); End;
Procedure Xuly;
var l,i,j:byte; d1:byte; Begin
l:=length(a);
a:=a+a[l]; {mục đích để thuật toán dùng A[L]}
j:=1;
for i:=2 to l
if not (((a[i-1]<a[i] ) and( a[i]>a[i+1] ))or ((a[i-1]>a[i] ) and( a[i]<a[i+1] ))) then Begin
d1:=i-j+1;
if d1>d then d:=d1; j:=i;
End;
if d=0 then d:=l; {Nếu có phần tử For chạy,nếu có phần tử For khơng chạy D=0 nen d lấy L=1}
End;
Procedure LuuKQ;
Begin
assign(output,fo); rewrite(output); write(d);
close(output); End;
Begin
DocDL; XuLy; LuuKq;
End.
Bài (4 điểm)
SUBARRAY
Cho dãy số nguyên a1, a2, … aN số nguyên dương K Dãy ai, ai+1, … aj
(1<=i<=j<=N) dãy tạo từ phần tử liên tiếp dãy A, phần tử i kết thúc phần từ j
Yêu cầu:Tìm số lượng dãy A có K phần tử Dữ liệu:Vào từ file văn bảnSUBARR.INP:
Dòng cứa số nguyên dương N, K (1<=k<=N<=4.105) Dòng thứ chứa N
số nguyên a1, a2, … aN(ai<=109)
Kết quả:Ghi file văn SUBARR.OUT: Ghi số lượng dãy tìm
(Các số dịng file liệu vào ghi ký tự
(8)- Về mặt liệu: Ai<=1.000.000.000 nên phải dùng Longint Byte
+ Gồm 400.000 phần tửBộ nhớ cần cấp 400.000 x = 1.600.000Bvượt mức cho
phép Pascal Đây vấn đề lớn, lẽ chương trình THPT hướng dẫn
khuôn khổ Pascal mà Nhưng thực tế phần mềm chấm điểm lại sử dụng
dịch Free Pascalvì bạncó thểkhai báo lớn nhiều sơ với Pascal
Đây điều thắc mắc đề thi năm gần Liệu có thuật
tốn mà sử dụng phạm vi Pascal để giải trường hợp tốn đặt
ra hay khơng?
Nếu bạn lo nhớ lớn khuyên tạora nhiều code vớicác liệu lớnvà nhỏ tách riêng Nhằm lấy tối đa Test
Một vấn đề là: dãy có 400.000 phầntử cả, với k=2 số lượng
dãy số có phần tử 400.000 + 399.999 + 399.998 + +1+0 ~= 40
tỷthì số Ngun khơng thể chứa ngoại trừ Int46 Free Pascal, Cịn khơng
ta sử dụng số thực với kiểu Double
Là câu khó vì:Ta phải kiểmtra tất cácdãy có độ dài lớn kvới số lượng phần tử 400.000 phần tử Thuật tốn khơng khó, chắn vấp
phải thời gian chạy (chạy thời gian xét dãy 1) - Thuật toán:
+ Ta sử dụng mảng để lưu Số lượng phần tử có dãy
+ Dãy xét i, bổ sung phần tử j vào, bổ sung phần tử tăng
biến đếm phần tử lên Nếu biến đếm = K ta thấy đoạn Ai Ajlà dãy
thảo mãnđoạn Ai Ajlà đoạn Ai ANnên ta có N-j+1 dãy
+ Ta tăng i lên để xét doạn tiếp theo, tăng i tức ta loại bỏ Aira khỏi danh sách cần từ biếm đếm phần tử Ai.Sau tăng i ta tiếp tục kiểm tra số lượng phần
tử dãy chỉ cần kiểm tra phần tử Aj(Loại bỏ giảm số lượng phần tử,
giảm phần tử vừa bổ sung Ajmới giảm)
Trong biến I chạy từ đến N-K +1; J chạy từ đến N biến chạy nhau, tuỳ trường hợp mà tăng không tăng nên ta phải dùng lặp While
Program SUBARRAY;
const fi='SUBARR.INP'; fo='SUBARR.OUT'; Var
A:Array[1 400000] of longint;
D:Array[1 1000000000] of word; {K~65000} sl:int64;
i,j,n,k:longint;
Procedure DocDL;
Begin
assign(input,fi); reset(input); readln(n,k);
(9)Procedure XuLy;
Begin i:=1; j:=0;
while (i<=n-k+1)and(j<=n) Begin
if D[A[j]]<k then 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;
Procedure LuuKq;
Begin
assign(output,fo); rewrite(output); write(sl);
close(output); End;
Begin
DocDL; XuLy; LuuKq;