You are on page 1of 6

ĐỀ BÀI NGÀY 07/11/2019

Bài 1. Tìm độ dài phủ các đoạn thẳng


Cho N (N≤104) đoạn thẳng trên trục số với tọa độ điểm đầu là xi và độ dài là di (các số |xi| và d
không vượt quá 109). Tính tổng độ dài trên trục số bị phủ bởi N đoạn thẳng đã cho.
Input. Length.inp: Dòng đầu là số nguyên dương N. N dòng tiếp theo, mỗi dòng là hai số xi và
di mô tả đoạn thẳng thứ i.
Output. Length.out: Một dòng ghi tổng dộ dài trên trục số bị phủ bởi N đoạn thẳng.
Hướng dẫn:
Sắp xếp các đoạn số theo điểm đầu xi, sau đó duyệt lần lượt từng đoạn một để tính tổng độ
dài bị phủ.
struct doanthang {
long x, d;
} A[maxN];
long N;
void read_input(){
fi.open(“KTHC_34.INP”);
fi >> N;
for (int i=0; i<N; i++)
fi >> A[i].x >> A[i].d;
fi.close();
}
int cmp (const void * dt1, const void * dt2) {
doanthang a, b;
a = *(doanthang *)dt1;
b = *(doanthang *)dt2;
return (a.x – b.x);
}
void process(){
long l, p;
fo.open(“KTHC_34.OUT”);
qsort(A, N, sizeof(doanthang), cmp);
l= A[0].d; // độ dài đoạn được phủ
p= A[0].x + A[0].d; // vị trí đã xét từ đầu tới đây
for (long i=1; i<N; i++)
if (p<A[i].x) {
l += A[i].d;
p = A[i].x + A[i].d;
}
else {
if (p< A[i].x + A[i].d) {
l += A[i].x + A[i].d – p;
p = A[i].x + A[i].d;
}
}
fo << l;
fo.close();
}
int main(){
read_input();
process();
return 0;
}
Bài 2. Trò chơi với dãy số - Seqgame
Hai bạn học sinh trong lúc nhàn rỗi nghĩ ra trò chơi sau đây. Mỗi bạn chọn trước một dãy số
gồm N số nguyên. Giả sử dãy số mà bạn thứ nhất chọn là:
b1, b2, …, bn
còn dãy số mà bạn thứ hai chọn là:
c1, c2, …, cn
Mỗi lượt chơi mỗi bạn đưa ra một số hạng trong dãy số của mình. Nếu bạn thứ nhất đưa ra
số hạng bi (1  i  N), còn bạn thứ hai đưa ra số hạng cj (1  j  N) thì giá của lượt chơi đó sẽ là
|bi+cj|.
Ví dụ: Giả sử dãy số bạn thứ nhất chọn là 1, -2; còn dãy số mà bạn thứ hai chọn là 2, 3. Khi
đó các khả năng có thể của một lượt chơi là (1,2), (1,3), (-2,2), (-2,3). Như vậy, giá nhỏ nhất của
một lượt chơi trong số các lượt chơi có thể là 0 tương ứng với giá của lượt chơi (-2,2).
Yêu cầu
Hãy xác định giá nhỏ nhất của một lượt chơi trong số các lượt chơi có thể.
Dữ liệu
 Dòng đầu tiên chứa số nguyên dương N (N  105)
 Dòng thứ hai chứa dãy số nguyên b1, b2, …, bn (|bi|  109,i=1, 2, …, N)
 Dòng thứ ba chứa dãy số nguyên c1, c2, …, cn (|ci|  109,i=1, 2, …, N)
Hai số liên tiếp trong một dòng được ghi cách nhau bởi dấu cách.
Kết quả
Ghi ra giá nhỏ nhất tìm được.
Ràng buộc
60% số test ứng với 60% số điểm của bài có 1  N  1000
Ví dụ
SEQGAME.IN SEQGAME.OUT
2 0
1 -2
2 3

Phân tích
+ Sắp xếp tăng từng dãy số
+ Dùng 2 biến chạy xuôi và ngược là i và j. Biến i dùng duyệt xuôi mảng b(N) bắt đầu từ vị
trí 1, biến j dùng duyệt ngược mảng c(N) bắt đầu từ vị trí N.
+ Vòng lặp thực hiện trong khi (i<=N) và (j>=1):
- Tính v=bi+cj
- Nếu v>=0 thì giảm j (để |v| giảm đi)
Ngược lại nếu v<0 thì tăng i (vì số âm khi được tăng lên thì trị tuyệt đối của nó
giảm đi.
Văn bản hương trình.
const fi = 'seqgame.in';
fo = 'seqgame.out';
max = 100000;
type tarray = array[1..max] of Integer;
var b, c : tarray;
n, min : integer;
procedure read_input;
var f : text;
i, temp : Integer;
begin
assign(f, fi); reset(f);
readln(f, n);
for i := 1 to n do read(f, b[i]);
readln(f);
for i := 1 to n do begin
read(f, c[i]);
end;
close(f);
end;
procedure quicksort(var k: TArray; l, r: Integer);
var i, j: integer;
temp, key: Integer;
begin
if l >= r then exit;
key := k[(l + r) div 2];
i := l; j := r;
repeat
while k[i] < key do inc(i);
while k[j] > key do dec(j);
if i <= j then begin
if i < j then begin
temp := k[i]; k[i] := k[j]; k[j] := temp;
end;
inc(i); dec(j);
end;
until i > j;
QuickSort(k, l, j);
QuickSort(k, i, r);
end;
procedure solve;
var v, i, j: integer;
begin
min := maxInt;
i:=1; j:= n;
while (i<=n) and (j>1) do begin
v := b[i]+c[j];
if v>=0 then dec(j)
else if v<0 then inc(i);
if abs(b[i]+c[j])<min then min:=abs(b[i]+c[j]);
end;
end;
procedure write_out;
var f: text;
begin
assign(f, fo); rewrite(f);
write(f, min);
close(f);
end;
BEGIN
read_input;
quicksort(b, 1, n);
quicksort(c, 1, n);
solve;
write_out;
END.
Bài 3. SỐ 0 CUỐI CÙNG
Cho một dãy số khoảng 1000000 kí tự số toàn 0 và 1. Biết rằng các số 0 đứng trước các chữ số 1:
000....0011...11. Hãy cho biết vị trí của số 0 cuối cùng trong dãy.
Thuật toán:
Ta tiến hành tìm kiếm nhị phân trên xâu kí tự để tìm ra vị trí số 0 cuối cùng như sau:
- Tìm phần tử giữa xâu đang xét
- So sánh kí tự ở vị trí giữa xâu với kí tự 0.
- Nếu kí tự giữa xâu là kí tự 0 thì ta tìm ở nửa sau của xâu, nếu không phải kí tự 0 (mà là 1)
thì ta tìm ở nửa trước của xâu.
1.d:=1; c:=length(s);
2. trong khi d<c thì
2.1 g:=(d+c+1) div 2;
2.2 Nếu s[g]='0' thì d:=g
2.3 Nếu s[g]='1' thì c:=g-1;
3.Quay lại bước 3
4.Kết thúc
Vậy vị trí của số 0 cuối cùng trong dãy là d
Bài 4. HÀNG CÂY
Trong khu vườn, người ta trồng một hàng cây chạy dài gồm có N cây, mỗi cây có độ cao là a 1,
a2,…aN.
Người ta cần lấy M mét gỗ bằng cách đặt cưa máy sao cho lưỡi cưa ở độ cao H (mét) để cưa tất cả
các cây có độ cao lớn hơn H (dĩ nhiên những cây có độ cao không lớn hơn H thì không bị cưa).
Ví dụ: Nếu hàng cây có các cây với độ cao tương ứng là 20; 15; 10 và 18 mét, cần lấy 7 mét gỗ.
Lưỡi cưa đặt tại độ cao hợp lí là 15 mét thì độ cao của các cây còn lại sau khi bị cưa tương ứng là
15; 15; 10 và 15 mét. Tổng số mét gỗ lấy được là 8 mét (dư 1 mét).
Yêu cầu: Hãy tìm vị trí đặt lưỡi cưa hợp lí (số nguyên H lớn nhất) sao cho lấy được M mét gỗ và
số mét gỗ dư ra là ít nhất.
Dữ liệu:
 Dòng thứ nhất chứa 2 số nguyên dương N và M (1≤N≤106; 1≤M≤2x109) cách nhau một dấu
cách.
 Dòng thứ hai chứa N số nguyên dương ai là độ cao của mỗi cây trong hàng (1≤ai≤109; i=1…N),
mỗi số cách nhau ít nhất một dấu cách.
Kết quả: Đưa ra màn hình một số nguyên cho biết giá trị cần tìm.
Ví dụ:
WOOD.INP WOOD.OUT
47 15
20 15 10 18
Thuật toán :
+ Đầu=0, cuối= chiều cao cây cao nhất.
+ Kiểm tra số mét gỗ S lấy được khi chặt ở độ cao h=(đầu+cuối) div 2:
- Nếu S=M: Thì in ra h và dừng chương trình.
- Nếu S<M thì đầu =h
- Nếu S>M thì cuối =h
- Tiếp tục kiểm tra h cho đến khi chênh lệch của M,S lặp lại.
writeln('Chieu cao cua cac cay la:');
for i:=1 to n do
begin
write('cay ',i,'=');readln(a[i]);
if a[i]>c then c:=a[i];
end;
d:=0;kt:=true;
while kt and (d<=c) do
begin
s:=0;
g:=(d+c) div 2;
for i:=1 to n do
begin
t:=a[i]-g;
if t>=0 then s:=s+t;
end;
t:=s-m;
if (t=0 )or (cl=t)then kt:=false
else begin
cl:=t;
if t<0 then c:=g else d:=g;
end;
end;
if t>=0 then write('h=',g) else write('ko tim dc');

You might also like