1. Trang chủ
  2. » Trung học cơ sở - phổ thông

DeOnTap OLP30 4 de01 02 solution (1)

17 42 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 17
Dung lượng 510,9 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

đề ôn tập olympic 304 cho học sinh trung học phổ thông, giáo viên, học sinh có thể tham khảo Câu 1. SUMMIN (6 điểm) Trên máy tính thời gian để thự hiện việc tính tổng của hai số nguyên dương là phụ thuộc vào giá trị của chúng. Giả sử khi cộng hai số nguyên dương x và y ta phải trả chi phí thời gian có giá trị bằng 5% giá trị của tổng hai số. Yêu cầu: Cho dãy A gồm N số nguyên dương a1, a2, ..., aN . Cần tìm cách tính tổng của các số này với tổng chi phí thời gian là nhỏ nhất. Input: SUMMIN.inp Dòng đầu tiên ghi số nguyên dương N (2  N  15000) Dòng tiếp theo ghi N số nguyên dương mà ta cần tính tổng, hai số liên tiếp được ghi cách nhau bởi ít nhất một dấu cách ( ai  105 , i =1..N). Output: SUMMIN.out Gồm một dòng ghi tổng chi phí theo cách thực hiện tính tổng tìm được. Kết quả được ghi với hai chữ số sau dấu chấm thập phân.

Trang 1

ĐỀ 01 Câu 1 SUMMIN (6 điểm)

Trên máy tính thời gian để thự hiện việc tính tổng của hai số nguyên dương là phụ thuộc vào giá trị của chúng Giả sử khi cộng hai số nguyên dương x và y ta phải trả chi phí thời gian có giá trị bằng 5% giá trị của tổng hai số

Yêu cầu: Cho dãy A gồm N số nguyên dương a1, a2, , aN Cần tìm cách tính tổng của các số này với tổng chi phí thời gian là nhỏ nhất

Input: SUMMIN.inp

- Dòng đầu tiên ghi số nguyên dương N (2  N  15000)

- Dòng tiếp theo ghi N số nguyên dương mà ta cần tính tổng, hai số liên tiếp được ghi cách nhau bởi ít nhất một dấu cách ( ai 105, i =1 N)

Output: SUMMIN.out

Gồm một dòng ghi tổng chi phí theo cách thực hiện tính tổng tìm được Kết quả được ghi với hai chữ số sau dấu chấm thập phân

Ví dụ:

SUMMIN.inp SUMMIN.out

2

1 1

0.10

5

1 7 4 9 2

2.35

HD:

- Để cộng N số lại với nhau, ta cần thực hiện các phép cộng (N-1 phép cộng)

- Nếu với mỗi phép cộng ta mất chi phí là bé nhất thì tổng N-1 phép cộng ta có tổng chi phí là bé nhất

- Sử dụng Heap_Min

-Tạo Heap_Min chứa n phần tử của dãy A: a1, a2, , aN

- Gọi Res là chi phí thời gian bé nhất cần tìm, khởi tạo

Res :=0;

- Lặp

Lấy ra hai phần tử bé nhất trong Heap_Min

x:=pop(1);

y:=pop(1);

Cộng chi phí tính tổng hai số x và y vào Res

Res:=Res+(x+y)*5/100;

Khi công hai số x và y sinh ra một giá trị mới (x+y), nạp giá trị (x+y) vào Heap_Min

push(x+y);

Cho đến khi Heap_Min còn 1 phần tử

Kết quả : Res

Trang 2

Program SUMMIN;

Const fi='SUMMIN.inp'; fo='SUMMIN.out';

Var f,g:text;

Res:Extended;

top,N,K:longint;

a:array[0 15000] of longint;

q:array[0 15000] of int64;

procedure doicho(i,j:longint);

var tg:int64;

begin

tg:=q[i];

q[i]:=q[j];

q[j]:=tg;

end;

procedure Up_heap(i:longint);

begin

if (i=1) then exit;

if (q[i div 2]>q[i]) then

begin

doicho(i,i div 2);

up_heap(i div 2);

end;

end;

procedure down_heap(i:longint);

var j:longint;

begin

j:=i*2;

if j > top then exit;

if (j<top)and(q[j]>q[j+1]) then j:=j+1;

if(q[i]>q[j]) then

Trang 3

up_heap(top);

end;

function pop(vitri:longint):int64;

begin

pop:=q[vitri];

q[vitri]:=q[top];

dec(top);

up_heap(vitri);

down_heap(vitri);

end;

Procedure Doc;

Var i,j:longint;

Begin

Assign(f,fi); reset(f);

Readln(f,N);

For i:=1 to N do Read(f,a[i]);

Close(f);

End;

Procedure Xuly;

Var i:Longint;

x,y:int64;

Begin

top:=0;

For i:=1 to N do push(a[i]);

Res:=0;

While top>1 do

Begin

x:=pop(1); y:=pop(1);

Res:=Res+(x+y)*5/100;

push(x+y);

End;

End;

Procedure ghi;

Var i,j:longint;

Begin

Assign(g,fo); Rewrite(g);

Writeln(g,Res:0:2);

Close(g);

End;

BEGIN

Trang 4

doc;

xuly;

ghi;

END

Trang 5

Câu 2 FGIRD (7 điểm)

Cho xâu S có độ dài 2N-1 và một lưới ô vuông A có kích thước NxN, mỗi ô trên lưới ghi một chữ cái Một người tìm cách di chuyển bắt đầu từ ô ở góc trên trái đến ô ở góc dưới phải, mỗi lần di chuyển chỉ được quyền sang ô có chung cạnh ở bên phải hoặc phía dưới sao cho các chữ cái trong các ô trên đường di chuyển tạo thành xâu S

Yêu cầu: Cho trước lưới ô vuông A và xâu S, hãy xác định số cách di chuyển thỏa mãn

yêu cầu đặt ra

Input: FGIRD inp

- Dòng đầu tiên ghi số N (2≤ N ≤1000);

- N dòng tiếp theo, mỗi dòng chứa N chữ cái Latin in thường (không nhất thiết phải khác nhau);

- Dòng cuối ghi xâu S gồm 2N-1 chữ cái Latin in thường

Output: FGIRD out

Gồm một dòng ghi số nguyên là phần dư của phép chia số cách di chuyển thỏa điều kiện cho 1000003

Ví dụ:

FGIRD inp FGIRD out

3 aaa aba baa aabaa

5

HD:

- Vị trí (i,j) trong bảng A tương ứng với vị trí (i+j)-1 trong xâu S

- Gọi L[i,j] là số cách di chuyển đến ô A[i,j] để thu được xâu con S[1 (i+j)-1]

- Khởi tạo L[0,1] = 1 và L[1,0] =0 hoặc L[0,1] = 0 và L[1,0] =1

- Công thức tính L[i,j]:

L[i,j] = 0 nếu a[i,j] <> s[i+j-1]

L[i,j] = L[i-1,j] + L[i, j-1] nếu a[i, j] = s[i+j-1]

- Kết quả L[n,n]

Chương trình tham khảo

const

fi='FGIRD.inp';

fo='FGIRD.out';

max=1000;

var f:text;

a:array[0 max] of ansistring;

s:ansistring;

n:longint;

Trang 6

l:array[0 max,0 max] of longint;

procedure doc;

var i,j:longint;

begin

assign(f,fi);reset(f);

readln(f,n);

for i:=1 to n do readln(f,a[i]);

readln(f,s);close(f);

end;

procedure xuly;

var i,j:longint;

begin

L[0,1] := 1;

L[1,0] :=0;

for i:=1 to n do

for j:=1 to n do

if a[i][j]=s[i+j-1] then l[i,j]:=(l[i,j-1]+l[i-1,j]) mod 1000003

else l[i,j]:=0;

end;

procedure ghi;

begin

assign(f,fo);rewrite(f);

write(f,l[n,n]);

close(f)

end;

begin

doc;

xuly;

ghi;

end

Trang 7

Câu 3 FGRAPH( 7 điểm )

Sống tại một thành phố lớn có mật độ dân số cao và giao thông phức tạp, ông Bình rất lo về nạn kẹt xe Để thuận tiện cho việc đi lại, ông Bình đang tìm hiểu các con đường ngắn nhất dẫn từ nhà đến cơ quan Bạn hãy giúp ông Bình thực hiện công việc kho khăn này

Bản đồ thành phố là gồm có N nút giao thông và M con đường hai chiều nối các nút giao thông này Độ dài của mỗi con đường là một số nguyên dương Nhà ông Binh ở nút giao thông 1, cơ quan ông bình ở nút giao thông N

Input: FGRAPH.inp

Dòng thứ nhất ghi hai số nguyên N và M (1 ≤ N ≤ 200, 1 ≤ M ≤ 20000)

M dòng tiếp theo, mỗi dòng ghi 3 số nguyên dương U, V, L ( con đường nối U đến V với độ dài L, L ≤ 32000)

Output: FGRAPH.out

Gồm một dòng ghi số lượng đường đi ngắn nhất

Ví dụ:

FGRAPH.inp FGRAPH.out

3 3

1 2 3

1 3 4

2 3 1

2

Thuật toán:

Áp dụng thuật toán Dijkstra

HD:

Gọi D[i] là độ dài đường đi ngắn nhất từ 1 đến i

Gọi Count[i] là số lượng đường đi ngắn nhất từ 1 đến i

Giả sử đã tìm được đường đi và số lượng đường đi ngắn nhất từ đỉnh 1 đến đỉnh u

Với mỗi đỉnh v là kề của u,

- Nếu đường đi 1  u  v ngắn hơn đường đi 1  v

Nếu D[v]> D[u]+a[u,v] thì

+ D[v]=D[u]+a[u,v]

+ Count[v] = Count[u]

- Nếu đường đi 1  u  v bằng đường đi 1  v

Nếu D[v]=D[u]+a[u,v] thì

+ L[v] = L[u] + L[v]

Count[n] là kết quả cần tìm

Chú ý: Luôn có đường đi từ 1 đến n

Chương trình tham khảo:

Trang 8

Program FGRAPH;

const

fi='FGRAPH.inp';

fo='FGRAPH.out';

maxn=200;

maxm=20000;

vc=1000000000;

var n,m: longint;

f: text;

d: array [-1 maxn+4] of longint;

count: array [-1 maxn+4] of int64;

dd: array [-1 maxn+4] of boolean;

c: array [1 maxn+4,1 maxn+4] of longint;

procedure doc;

var i,j,u,v,t: longint;

begin

assign(f,fi); reset(f);

fillchar(c,sizeof(c),0);

readln(f,n,m);

for i := 1 to n do

for j := 1 to n do

if i = j then c[i, j] := 0

else c[i, j] := vc;

for i := 1 to m do

begin

Readln(f, u, v, t);

if c[u,v] > t then

begin

c[u,v] := t;

c[v,u] := t;

end;

Trang 9

for i:=1 to n do d[i]:=vc;

d[1]:=0;

repeat

u := 0; min := vc;

for i := 1 to n do

if dd[i] and (d[i] < min) then

begin

min := d[i];

u := i;

end;

if (u = 0) then Break;

dd[u]:=false;

for v := 1 to n do

if dd[v] then

if (d[v] > d[u] + c[u, v]) then

begin

d[v] := d[u] + c[u, v];

count[v]:=count[u];

end

else if (d[v]=d[u]+c[u,v]) then count[v]:=count[v]+count[u];

until False;

end;

procedure ghi;

var i: longint;

begin

assign(f,fo); rewrite(f);

write(f,count[n]);

close(f);

end;

BEGIN

doc;

dijkstra;

ghi;

END

Trang 10

ĐỀ 02 Bài 1:

Duyệt kết hợp chặt nhị phân

Bài 2: Bánh sinh nhật

Nhận xét: Giả sử x[i] là vị trí cuối cùng Bình dừng lại ăn bánh để đạt kết quả tối

ưu Ta luôn tốn 1 khoảng thời gian để đi từ 0 đến x[i], gọi thời gian đó là T0 Công việc còn lại cần làm là tìm cách ăn bánh sao cho số bánh ăn được là nhiều nhất Dễ dàng nhận thấy chỉ việc chọn ăn những bánh nhỏ nhất sao cho tổng thời gian ăn bánh + T0 <= T

Sử dụng cấu trúc Heap max để lưu trữ thời gian cần để ăn hết các bánh Duyệt trên trục toạ độ thử các vị trí i là vị trí cuối cùng Bình dừng lại ăn bánh, đi qua vị trí nào thì push hết bánh ở vị trí đó vào Heap, cập nhật lại Heap Chừng nào T0 + (tổng thời gian để ăn hết tất cả bánh có trong Heap) > T thì pop bánh có thời gian ăn lớn nhất ra Sau đó cập nhật lại kết quả tối ưu

Bài 3:

Phát biểu ngắn

Cho đồ thị có hướng có trọng số dương trên cung G=(V,E, C), hai đỉnh (s,t) và tập cạnh A={ (ui, vi), i=1,2, ,k}

Cần chọn cạnh e  A sao cho việc bổ sung nó vào đồ thị G làm cho độ dài đường đi

từ s đến t giảm được nhiều

Thuật toán:

Tính d1(s,v) độ dài đường đi ngắn nhất từ s đến v, v  V \ { s} (1)

Tính d2(v,t) độ dài đường đi ngắn nhất từ v đến t, v  V \ { t} (2)

Tính

Kq1:=min { d1(s,u) + c(u,v) + d2(v,t) : (u,v)  A}

Kq2: =min { d1(s,v) + c(u,v) + d2(u,t) : (u,v)  A} (3)

Khi đó kq:=min(kq1,kq2, d1(s,t)) là đáp số cần tìm

CHƯƠNG TRÌNH THAM KHẢO

Chương trình đề nghị giải Bài 1

{$Mode ObjFPC}

Const fi='GROUP.INP';

fo='GROUP.OUT';

nMax=51;

Trang 11

Assign(f,fi);

Reset(f);

Readln(f,n,k);

aMax:=0;

For i:=1 to n do

Begin

Read(f,a[i]);

aMax:=aMax+a[i];

End;

Close(f);

aMax:=aMax div k +1;

End;

Function Check(u:int64):boolean;

Begin

Sum:=0;

b:=a;

For i:=1 to n do

Begin

If b[i]>u then b[i]:=u;

Sum:=Sum+b[i];

End;

Exit(Sum>=u*k);

End;

Procedure Main;

Begin

Low:=0; High:=aMax;

While Low<High do

Begin

Mid:=(Low+High+1) div 2 ;

If check(Mid) then Low:=Mid else

High:=Mid-1;

End;

Res:=High;

End;

Procedure Print;

Begin

Assign(f,fo);

Rewrite(f);

Writeln(f,Res);

Close(f);

End;

Begin

Enter;

Trang 12

Main;

Print;

ENd

Chương trình đề nghị giải Bài 2

Program ANNICAKE;

CONST FINP = 'ANNICAKE.INP'; FOUT = 'ANNICAKE.OUT';

VAR fi,fo:text;

num,N,res:longint;

Sum,TK:int64;

H,X,T:array[1 100005] of longint;

Procedure UpHeap(x:longint);

Var c,tmp:longint;

BEGIN

tmp := H[x];

c := x div 2;

while (c>0)and(T[H[c]]<T[tmp]) do

begin

H[x] := H[c];

x := c;

c := x div 2;

end;

H[x] := tmp;

END;

Procedure Add(x:longint);

BEGIN

inc(num);

H[num] := x;

Sum := Sum+T[x];

UpHeap(num);

END;

Procedure DownHeap(x:longint);

Var c,tmp:longint;

BEGIN

tmp := H[x];

Trang 13

BEGIN

x := H[1];

H[1] := H[num];

dec(num);

DownHeap(1);

Sum := Sum-T[x];

END;

Procedure Process;

Var i,u:longint;

BEGIN

readln(fi,N,TK);

for i:=1 to N do readln(fi,X[i],T[i]);

for i:=1 to N do

begin

Add(i);

While((Sum+X[i])>TK)and(num>0) do Get(u);

if res < num then res := num;

end;

writeln(fo,res);

END;

BEGIN

assign(fi,FINP); assign(fo,FOUT);

Process;

close(fi);

close(fo);

END

Chương trình đề nghị giải Bài 3

Program TRANSNET;

CONST FINP = 'TRANSNET.INP'; FOUT = 'TRANSNET.OUT'; Ulti = trunc(1e9); maxN = 11001; maxM = 110001;

VAR fi,fo:text;

N,M,K,S1,T1,res:longint;

x,y,z:array[0 maxM] of longint;

head:array[1 2,0 maxN] of longint;

A,C:array[1 2,0 maxM] of longint;

num:array[1 2] of longint;

H,L,id:array[1 2,0 maxM] of longint;

dd:array[1 2,0 maxN] of boolean;

Procedure INIT;

Var i:longint;

BEGIN

readln(fi,N,M,K,S1,T1);

for i:=1 to M do

begin

Trang 14

readln(fi,x[i],y[i],z[i]);

inc(head[1][x[i]]);

inc(head[2][y[i]]);

end;

for i:=1 to N+1 do

begin

head[1][i] := head[1][i-1] + head[1][i];

head[2][i] := head[2][i-1] + head[2][i];

end;

for i:= 1 to M do

begin

A[1][head[1][x[i]]] := y[i];

A[2][head[2][y[i]]] := x[i];

C[1][head[1][x[i]]] := z[i];

C[2][head[2][y[i]]] := z[i];

dec(head[1][x[i]]);

dec(head[2][y[i]]);

end;

END;

Procedure UpHeap(z,x:longint);

Var tmp,c:longint;

BEGIN

tmp := H[z][x];

c := x div 2;

while(c>0) and (L[z][tmp]<L[z][H[z][c]]) do

begin

H[z][x] := H[z][c];

id[z][H[z][x]] := x;

x := c;

c := x div 2;

end;

H[z][x] := tmp;

id[z][H[z][x]] := x;

END;

Procedure DownHeap(z,x:longint);

Var tmp,c:longint;

Trang 15

x := c;

end;

H[z][x] := tmp;

id[z][H[z][x]] := x;

END;

Procedure Add(z,x:longint);

BEGIN

if(id[z][x]>0) then UpHeap(z,id[z][x])

else

begin

inc(num[z]);

H[z][num[z]] := x;

id[z][x] := num[z];

UpHeap(z,num[z]);

end;

END;

Procedure Get(z:longint;Var x:longint);

BEGIN

if (num[z]=0) then

begin

x := 0;

Exit;

end;

x := H[z][1];

H[z][1] := H[z][num[z]];

id[z][H[z][1]] := 1;

dec(num[z]);

DownHeap(z,1);

END;

Procedure Edit(z,u:longint);

Var i:longint;

BEGIN

for i:=head[z][u]+1 to head[z][u+1] do

if not dd[z][A[z][i]] then

begin

if (L[z][A[z][i]] > L[z][u] + C[z][i]) then

begin L[z][A[z][i]] := L[z][u] + C[z][i];

Add(z,A[z][i]);

end;

end;

END;

Procedure Dijkstra(z,S:longint);

Var i,u:longint;

Trang 16

BEGIN

for i:=1 to N do L[z][i] := Ulti;

dd[z][S] := true;

L[z][S] := 0;

Add(z,S);

repeat

Get(z,u);

if (u=0) then break;

dd[z][u] := true;

Edit(z,u);

until(u=0);

END;

Function Cal(x,y,z:longint):longint;

Var S:longint;

BEGIN

if(L[1][x] = Ulti) or (L[2][y] = Ulti) then Exit(Ulti);

S := z + L[1][x] + L[2][y];

Exit(S);

END;

Procedure Process;

Var i,x,y,z,tmp:longint;

BEGIN

INIT;

res := Ulti;

Dijkstra(1,S1);

Dijkstra(2,T1);

if res > L[1][T1] then res := L[1][T1];

if res > L[2][S1] then res := L[2][S1];

for i:=1 to K do

begin

readln(fi,x,y,z);

tmp := Cal(x,y,z);

if res > tmp then res := tmp;

tmp := Cal(y,x,z);

if res > tmp then res := tmp;

end;

Trang 17

END

Ngày đăng: 22/10/2021, 10:18

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

  • Đang cập nhật ...

TÀI LIỆU LIÊN QUAN

w