You are on page 1of 62

K THUT PHN TCH THIT K GII THUT

CHO CC CUC THI LP TRNH


Phm Nguyn Khang
pnkhang@cit.ctu.edu.vn

MC LC
1 Phng php lu tha ma trn .......................................................................................... 1
1.1 Tm s Fibonacci ............................................................................................................................ 1
1.2 Tnh lu tha ca mt s ............................................................................................................. 2
1.3 Tnh lu tha ca mt ma trn vung ..................................................................................... 3
1.4 Gii bi 10229 - Modular Fibonacci ........................................................................................ 3
1.5 Bi hc kinh nghim ..................................................................................................................... 4
1.6 Cc bi tng t ............................................................................................................................. 4
1.7 M ngun cho bi 10229 .............................................................................................................. 4
2 Quy hoch ng ........................................................................................................................ 5
2.1 Gii thiu .......................................................................................................................................... 5
2.2 Bi ton sn nh ............................................................................................................................. 5
2.3 Bi hc kinh nghim ..................................................................................................................... 6
2.4 Cc bi tng t ............................................................................................................................. 7
3 S hc ng d ....................................................................................................................... 13
3.1 Chia ht v chia c d ................................................................................................................ 13
3.2 S nguyn t .................................................................................................................................. 14
3.3 Bi ton t-prime .......................................................................................................................... 15
3.4 Phn tch mt s thnh tch cc tha s nguyn t ......................................................... 16
3.5 S d ca (a/b) % MOD ............................................................................................................ 21
4 Cy phn on (Segment Tree/Interval Tree) ............................................................ 24
4.1 Bi ton tnh trung bnh nhanh .............................................................................................. 24
4.2 Ci t interval tree ................................................................................................................... 24
4.3 Gii bi tnh trung bnh nhanh ............................................................................................... 25
4.4 Bi hc kinh nghim .................................................................................................................. 30
4.5 Cc bi tng t .......................................................................................................................... 30
4.6 Cc bi nng cao .......................................................................................................................... 30
5 Tm kim tam phn (Ternary Search) .......................... Error! Bookmark not defined.
5.1 Bi ton khong cch ngn nht ............................................................................................ 48
5.2 Bi tng t ................................................................................................................................. 50
6 Gii thut trn th ............................................................................................................ 52
6.1 Gii thut Dijkstra tm ng i ngn nht ....................................................................... 52
6.2 Gii thut Kruskal tm cy khung c trng s nh nht ................................................. 56
7 Cn tip ... ............................................................................... Error! Bookmark not defined.

K thut phn tch v thit k gii thut

Phng php lu tha ma trn

1.1 Tm s Fibonacci

Xt bi ton 10229 - Modular Fibonacci trn UVA nh sau:


Problem A: Modular Fibonacci
The Fibonacci numbers (0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...) are defined by the recurrence:
F0 = 0
F1 = 1
Fi = Fi-1 + Fi-2 for i>1
Write a program which calculates Mn = Fn mod 2m for given pair of n and m. 0 n
2147483647 and 0 m< 20. Note that a mod b gives the remainder when a is divided by b.
Input and Output
Input consists of several lines specifying a pair of n and m. Output should be
corresponding Mn, one per line.
Sample Input
11 7
11 6
Sample Output
89
25
Yu cu ca bi ton kh n gin l tnh Fn mod 2m. Ta c th ngh ngay n mt li gii
nh sau:
- Tnh s fibonacci th n => Fn.
- Chia Fn cho 2m ly phn d => kt qu.
int F0= 0, F1 = 1, F2;
for (int i = 2; i <= n; i++) {
F2 = F0 + F1;
F0 = F1;
F1 = F2;
}
cout << F2 % (1<< m); // 1<< m = 2m.
Tuy nhin, nu bn ci t n gin nh th v submit chc chn s b Time limit exceeded
!. Vy vn nm u ? Chc chn l ch tnh Fn ri v bc 2 ch n gin l php chia
ly phn d. Phn tch li on code trn ta thy thi gian tnh Fn l O(n) v vng lp for
chy khong n ln. C cch no tnh Fn m tn t vng lp hn khng ? O(logn) chng hn ?
C mt cch nh th !
Ta th vit li cng thc tnh cc s Fibonaccii.
Fn
= Fn-1 + Fn-2
Fn+1 = Fn + Fn-1
Sp xp li cc F vo mt ma trn 2 x 2 ta c:
!!!
!
!!!
1 1 !
=
(1)
!
!!!
1 0 !!! !!!
Thay
F!
F!!!
1 1 F!!! F!!!
=
(2)
F!!! F!!!
1 0 F!!! F!!!
vo (1) ta c:
!!!
!
1 1 ! !!! !!!
=
(3)
!
!!!
1 0 !!! !!!
1/61

K thut phn tch v thit k gii thut

Tip tc trin khai:

!!!
!

!
1 1
=
!!!
1 0

! !
(4)
! !!
1 1!
Vy Fn (hng 2 ct 1)= hng cui ca ma trn
nhn vi ct u tin ca ma trn
1 0
! !
1
1 1!
hay
= phn t hng 2 ct 1 ca ma trn
.
! !!
0
1 0
Ch l trong cng thc (4), gi tr ca F-1 bng bao nhiu khng quan trng v ta khng s
dng n tnh Fn.
1 1!
Tm li tnh Fn ta tnh
v ly phn t hng 2 ct 1.
1 0
1 1!
Nh th, thay v tnh Fn ta tnh
. Tnh lu tha ca ma trn nh th no ? C nhanh
1 0
hn tnh Fn trc tip khng ?

1.2 Tnh lu tha ca mt s

phn tch thi gian tnh lu tha ca ma trn, ta quay li bi ton tnh lu tha ca mt s
(s l ma trn 1 hng 1 ct).
Gii thut n gin tnh lu tha ca mt s (xn) l:
int lt = 1;
for (int i = 1; i <= n; i++) {
lt = lt*x;
}
return x;
Vng lp for ny vn chy n ln => thi gian chy vn l O(n). Vy th c g hay hn tnh s
Fibonacci trc tip ? C cch no tnh xn nhanh hn khng ?
Tnh xn bng cch nhn lin tip nh trn ta cn n php nhn. Gi s n l s chn, ta vit li:
xn = xn/2 * xn/2
Nh th s php nhn s gim bt gn . Nu n l s l, xn = xn-1*x, xn-1 s c tnh nh
trng hp n chn.
Gii thut quy tnh xn nh bn di.
int power(int x, int n) {
if (n == 0) return 1;
if (n % 1) return power(x, n-1) * x;
int temp = power(x, n/2);
return temp*temp;
}
Mt tip cn khc tnh xn bng phng php lp nh sau.
Gi s bk-1 bk-2 b1 b0 l biu din nh phn ca n, ta c
xn = x(bk-1 bk-2 b1 0) * xb0 = x2(bk-1 bk-2 b1) * xb0 = (x^2) (bk-1 bk-2 b1) * xb0 =
((x^2)^2) (bk-1 bk-2 b2) * (x^2) b1 * xb0 =
(vi (x^2) = x2).
Nh th ta thy rng nu b0 = 1 ta nhn kt qu vi x. K tip, loi b bit cui cng i. Sau
cng thay x bng x^2.

2/61

K thut phn tch v thit k gii thut

Gii thut lp tnh xn nh sau:


int result = 1;
while (n > 0) {
if (n % 2 == 1) result = result * x;
x = x*x;
n >>= 1;
}

1.3 Tnh lu tha ca mt ma trn vung


Ta c th m rng gii thut tnh lu tha bng phng php lp cho vic tnh lu tha mt
ma trn. Vic m rng kh n gin. Ta thay 1 bng ma trn n v, php nhn bng php
nhn ma trn.
Matrix result = I; //I l ma trn n v
while (n > 0) {
if (n % 2 == 1) result = multiply(result, x);
x = multiply(x, x);
n >>= 1;
}

1.4 Gii bi 10229 - Modular Fibonacci


Gi y ta c thng tin gii bi ton Modular Fibonacci.
Biu din ma trn: s kh ln nn dng kiu long long hoc (unsigned long long) cho chc n

Matrix =

struct Matrix {
long long a, b, c, d;
};
To ma trn n v
void identity(Matrix& I) {
I.a = I.d = 1;
I.b = I.c = 0;
}
Nhn ma trn
Matrix multiply(Matrix A, Matrix
Matrix C;
C.a = (A.a*B.a + A.b*B.c) %
C.b = (A.a*B.b + A.b*B.d) %
C.c = (A.c*B.a + A.d*B.c) %
C.d = (A.c*B.b + A.d*B.d) %
return C;
}
Vi mod = 2m = (1<<m);

3/61

B) {
mod;
mod;
mod;
mod;

K thut phn tch v thit k gii thut

1.5 Bi hc kinh nghim


-

Tnh lu tha ca 1 s hoc 1 ma trn bng phng php lp hoc quy c phc
tp thi gian O(logn). Ta lm c iu ny v 2 l do:
o Ta ch cn tnh xn m khng cn phi tnh tt c x1, x2, , xn-1 nn khng cn
phi duyt qua tt c cc con s t 1 n n.
o Tch bi ton ln thnh 2 bi ton nh ging nhau nn ch cn gii 1 bi.
a bi ton tm s Fibonacci v bi ton tm lu tha nh vo cch biu din ma
trn.

1.6 Cc bi tng t
-
-

Light Oj (http://lightoj.com): ch Matrix/Matrix Exponentiation

1.7 M ngun cho bi 10229


Gi y ta c thng tin bi ton Modular
No ta cng submit !!!!
#include <iostream>
using namespace std;
long long mod;
struct Matrix {
long long a, b, c, d;
};
Matrix F;
void identity(Matrix& I) {
I.a = I.d = 1;
I.b = I.c = 0;
}
Matrix multiply(Matrix A, Matrix B) {
Matrix C;
C.a = (A.a*B.a + A.b*B.c) % mod;
C.b = (A.a*B.b + A.b*B.d) % mod;
C.c = (A.c*B.a + A.d*B.c) % mod;
C.d = (A.c*B.b + A.d*B.d) % mod;
return C;
}
long long process(long long n, int m) {
mod = (1 << m);
Matrix R;
identity(R);
while (n > 0) {
if (n%2) R = multiply(R, F);
F = multiply(F, F);
n >>= 1;
}
return R.c;
}
int main() {
long long n, m;
while (1) {
cin >> n >> m;
4/61

K thut phn tch v thit k gii thut

if (cin.fail())
break;
if (n <= 1)
cout << n << endl;
else {
F.a = F.b = F.c = 1; F.d = 0;
cout << process(n, m) << endl;
}

}
return 0;

Quy hoch ng

2.1 Gii thiu

Quy hoch ng l mt k thut c dng thit k cc gii thut c phc tp thi gian
thp (a thc) bng cch lu tr cc kt qu trung gian. Ta c th s dng k thut ny bng
2 cch:
-
-

Dng quy hoch ng kh quy v gim thi gian thc hin


Phn tch trc tip bi ton bng quy hoch ng

2.2 Bi ton sn nh
1047 - Neighbor House
The people of Mohammadpur have decided to paint each of their houses red, green, or
blue. They've also decided that no two neighboring houses will be painted the same color.
The neighbors of house i are houses i-1 and i+1. The first and last houses are not
neighbors.
You will be given the information of houses. Each house will contain three integers "R G
B" (quotes for clarity only), where R, G and B are the costs of painting the corresponding
house red, green, and blue, respectively. Return the minimal total cost required to perform
the work.
Input
Input starts with an integer T ( 100), denoting the number of test cases.
Each case begins with a blank line and an integer n (1 n 20) denoting the number of
houses. Each of the next n lines will contain 3 integers "R G B". These integers will lie in
the range [1, 1000].
Output
For each case of input you have to print the case number and the minimal cost.
Sample Input
2
4
13 23 12
77 36 64
44 89 76
5/61

K thut phn tch v thit k gii thut

31 78 45
3
26 40 83
49 60 57
13 89 99
Output for Sample Input
Case 1: 137
Case 2: 96
C n cn nh cn sn. Mi cn nh c sn bng 1 trong 3 mu R, G, B vi 3 mc gi
tng ng. Phi sn lm sao cho hai cn nh cnh nhau khng cng mu v tng gi t nht.
Gi r[i], g[i] v b[i] l cc gi tng ng nu sn cn nh i bng cc mu R, G, B.
phn tch cc bi dng nh th ny ta chia bi ton thnh n bc ng vi n cn nh. Ti
bc i, ta gi s cc cn nh t 1 n (i-1) c sn ri v tng gi t cn 1 n (i-1) cng
bit ri. Nu cn nh th (i-1) sn mu R v c tng gi t 1 n (i-1) l R(i-1); nu cn
nh th (i-1) sn mu G c tng gi l G(i-1) v nu sn mu B c tng gi B(i-1) th:
-
-
-

Cn nh th i sn mu R c tng gi l R(i) = min (G(i-1), B(i-1)) + r[i]


Cn nh th i sn mu G c tng gi l G(i) = min (R(i-1), B(i-1)) + g[i]
Cn nh th i sn mu B c tng gi l B(i) = min (G(i-1), R(i-1)) + b[i]

Vy gi nh nht sn n cn nh l = min(R(n), G(n), B(n));


Khi to R(0) = G(0) = B(0) = 0;

2.3 Bi hc kinh nghim


-

Rt nhiu bi ton c th gii bng k thut quy hoch ng. Cc bi ton quy hoch
ng thng lin quan n vic tm ln nht, nh nht, tng s.

Cch tip cn gii l chia bi ton thnh nhiu bc, mi bc l mt bi ton con
tng t nhau. Ti mi bc ta c 1 s s la chn.

mi bc, s dng thng tin c tch lu cc bc trc tnh ton kt


qu cho bc hin ti. Lu kt qu ca bc hin ti dnh cho cc bc sau.

C gng biu din thng tin cn lu tr ti tng bc sao cho vic tnh ton kt qu
ti bc i ch cn s dng cc thng tin tng hp ca cc bc t 1 n i-1. Hay nht
l tnh bc i ta ch cn thng tin ca bc i-1 (khng phi bi no cng ri v
trng hp ny).

Nu cc s la chn bc i khng ph thuc vo cc s la chn ca cc bc


trc th y l bi ton d. Nu c s rng buc gia cc la chn, c gng biu
din sao cho cc s la chn bc i ch nn c rng buc vi cc la chn bc i
1 m thi. Nu khng lm c nh vy ta khng th s dng quy hoch ng
(trng hp ny ging nh vt cn, phi xt ht tt c cc trng hp). V nu c s
dng c cng khng tit kim c thi gian. Trong bi ton coin change, s la
chn ca bc i khng ph thuc vo bt c s la chn no trc . i vi bi
ton sn nh, s la chn bc i ch ph thuc vo s la chn bc i-1 m
khng quan tm n s la chn cc bc i-2, i-2,
6/61

K thut phn tch v thit k gii thut

i vi 1 s bi ton, biu din cc s la chn l mt vn ta cn phi quan tm.


Nu biu din khng kho, s la chn s ln n an hoc n! (xem bi Agent 47 bn
di).

2.4 Cc bi tng t
-

Light Oj: Nhm Divide and conquer/Dynamic programming

1231 Coin Change (I): tm s cch to s tin c gi tr K bng cch dng cc ng tin c
mnh gi: A1, A2 ... An v mi mnh gi c s lng C1, C2, ... Cn.
Ta chia bi ton thnh n bc, mi bc ta xt tng loi mnh gi.
bc i, ta xt ng tin c mnh gi A[i], ta cc s la chn sau:
Chn 0 ng c mnh gi A[i]
Chn 1 ng c mnh gi A[i]

Chn k ng c mnh gi A[i], k = min(C[i], K/A[i]). Ta ch c th chn


nhiu nht l k ng.

o
o
o
o

Vi mi s la chn nh th, v d chn j ng c mnh gi A[i], s tin cn li l K


j*A[i]. Vy s cch to ra s tin c gi tr K vi la chn j ng mnh gi A[i] s l s
cch to ra K j*A[i] vi i-1 mnh gi cn li. Nu gi F[i][K] l s cch to ra s tin
c gi tr K vi i mnh gi, th:
F[i][K] = tng F[i-1][K-j*A[i]] vi j = 0, 1, 2, , k = min(C[i], K/A[i]).
Khi to:
F[i][0] = 1, F[0, j>0] = 0;
1232 Coin Change (II): tm s cch to s tin c gi tr K bng cch dng cc ng tin
c mnh gi: A1, A2 ... An v mi mnh gi c s lng K.
Bi ny tng t bi 1231, tuy nhin do s lng cho mi mnh gi l K v mi mnh gi
u >= 1 nn ta c th xem nh s lng mi mnh gi l khng hn ch.
Cng thc cho bc i c th vit li nh sau:
F[i][K] = tng F[i-1][K-j*A[i]] =
= F[i-1][K - k*A[i]] + F[i-1][K - (k-1)*A[i]] + + F[i-1][K - A[i]] + F[i-1][K]
= F[i][K-A[i]] + F[i-1][K];
Nhn xt ny kh quan trng v ta khng cn phi tnh tng F[i-1][K-j*A[i]] (b bt
c 1 vng lp).
1004 - Monkey Banana Problem: tm ng i cho ch kh thu c nhiu chui nht.
Bt u trn cng n di cng. Quy tc i: i xung v ch i n 1 trong cc c
chung cnh vi hin ti.

7/61

K thut phn tch v thit k gii thut

u vo: N v 2*N 1 hng, mi hng cha cc s ca hng .


u ra: tng s chui nhiu nht.
Nu ta nh s cc hng t trn xung di, bt u t 1v canh l tt cc cc hng v bn
tri ta s mt hnh nh th bn di. Gi bng ny l A[i, j].
1

10

12

12

10

Nhn xt:
-
-
-

T hng 1 n hng N-1, s phn t tng dn. T hng N n hng 2N-1 s phn t
gim dn.
Cc hng t 2 n N, (i, j) nu j < i th c chung cnh vi (i-1, j-1) v (i-1, j)
ngc li n l phn t cui cng, ch chung cnh vi (i-1, j-1).
Cc hng t N+1 n 2N-1, (i, j) c chung cnh vi (i-1, j) v (i-1, j+1).

p dng k thut quy hoch ng:


Ta chia bi ton thnh N bc, mi bc xt 1 hng. hng i, ta ln lc xt cc (i, j) v
tnh xem i n th con kh thu c nhiu nht bao nhiu chui.
Nu gi F[i, j] l tng s chui nhiu nht m con kh thu c t hng 1 n (i, j), ta c:
F[i, j] = max {F[i-1, k]} + A[i, j]
Vi (i-1, k) l cc c chung cnh vi (i, j). Cc chung cnh c tnh theo nhn xt
bn trn.
Kt qu cui cng thu c F[2N-1][1]
Cc bn th ci t v submit nh !

8/61

K thut phn tch v thit k gii thut

1017 - Brush (III): Samir cn phi sn mt bc tng xo cc im bi. Bi nm ti cc


to nguyn. C sn c kch thc w. Nu Samir t c ti to y* (khng quan tm n
x) th tt c im bi c to y nm trong khong y* n y* + w u c xo. Sau khi t
c v sn xo bi, Samir li tip tc t c ti mt v tr khc v sn tip. Tuy nhin Samir
ch c th sn ti a k ln. Hy tm tng s im bi ln nht m Samir c th xo.

Sp xp cc im bi theo th t tung gim dn y[1], y[2], , y[n].

Ta chia bi ton thnh n bc, mi bc xt 1 im bi. Gi F[i, k] l s im bi nhiu nht


b xo tnh t 1 n i vi k ln sn. mi bc i, ta c 2 s la chn:
-
-

B qua im bi i, s im bi b xo nhiu nht l F[i, k] = F[i-1, k]


t c ti v tr tung ca i, tt c cc im bi t y[i] n y[i] w s b xo ht. S
ln sn ch cn li k 1. Gi j l im bi c tung va ln y[i] w, s im bi
nhiu nht b xo vi la chn l F[I, k] = F[j, k-1] + (i j).

Gii thut quy hoch ng s nh sau:


long long process(int n, int w, int K) {
memset(F, 0, sizeof(F));
for (int i = 1; i <= n; i++) {
F[i][0] = 0;
for (int k = 1; k <= K; k++) {
int j = i;
while (j >= 1)
if (y[j] <= y[i] + w)
j--;
else
break;
F[i][k] = std::max(F[j][k-1] + (i - j), F[i-1][k]);
}
}
return F[n][K];
}
1169 - Monkeys on Twin Tower
C mt to thp i, mi thp c n tng. Tng trt c nh s 0, tng k tip c nh s
1, , tng cui cng c nh s n-1. Mi tng c mt s tri cy. Con kh trc bit thi
gian n ht tri cy cc tng. u tin con kh tng trt, mi ln n c th nhy ln tng
trn n ca cng 1 to thp vi thi gian xem nh bng khng, hoc i theo cu thang xon
9/61

K thut phn tch v thit k gii thut

ln tng trn ca to thp kia vi mt khong thi gian t no . Nhim v ca con kh l


phi n ht tri cy ca ng n tng. Tnh thi gian t nht con kh hon thnh nhim v.
V d:
Tng

TG n cc tng
bn thp tri

TG n cc tng
bn thp phi

TG nhy t tng i
ca thp tri sang
tng (i+1) thp phi

TG nhy t tng i
ca thp phi sang
tng (i+1) thp tri

L[i]
9
8
6
5

R[i]
10
3
9
7

L2R[i]

R2L[i]

3
2
5

3
4
2

3
2
1
0
Kt qu: 26

Ta chia bi ton thnh n bc, mi bc xt mt tng. bc i, con kh c th to thp tri


hoc to thp phi. Vi mi v tr bc i, trc bc i-1 n c th tng tri hoc thp
phi. Gi FL[i] l thi gian nh nht con kh tng i ca thp bn tri v FR[i] l thi gian
nh nht con kh tng i to thp bn phi, ta c:
- FL[i] = min (FL[i-1], FR[i-1] + R2L[i-1]) + L[i]
- FR[i] = min (FR[i-1], FL[i-1] + L2R[i-1]) + R[i]
Nu n ang tng i ca to thp tri, nu trc 1 bc n cng to thp tri th khng
cn phi cng thm thi gian nhy t phi sang tri, ngc li ta phi cng thm thi gian
ny. L lun tng t cho trng hp n tng i ca to thp phi.
Cc bn th code v submit nh.

10/61

K thut phn tch v thit k gii thut

1037 Agent 47: Cho n mc tiu (1<= n <= 15), mi mc tiu c ch s sc kho l A1, A2,
, An. Nhim v ca Agent 47 l phi tiu dit ht tt c cc mc tiu. u tin Agent c
trang b 1 v kh c kh nng lm tiu hao 1 n v sc kho trn 1 ln bn. Mt mc tiu s
b tiu dit nu ch s sc kho ca n <= 0. Mi khi tiu dit c 1 mc tiu, agent c th
thu gom v kh ca mc tiu tiu dit cc mc tiu khc. V kh ca mt mc tiu c
tc dng khc nhau trn tng mc tiu khc. Gi Cij l kh nng lm tiu hao sc kho ca v
kh (ca mc tiu) i trn mt ln bn i vi mc tiu j, 0 <= Cij <=9. Tm cch cho agent 47
tiu dit ht tt c cc mc tiu vi s ln bn t nht.
Bi ny thuc dng kh. Ta th phn tch cc vn sau:
-
-

Chia bi ton thnh n bc nh th no ? Mi bc l g ?


S la chn cho tng bc nh th no ? Vi mi la chn, tnh ton thng tin ta
cn thng tin g bc i-1.

Nu ta chia bi ton thnh n bc, mi bc chn 1 mc tiu tiu dit, th vic la chn
mc tiu bc i s ph thuc vo cc bc trc mc tiu no c chn.
K thut quy hoch ng s p dng c trong trng hp ny nu s cch la chn
ca tt c cc bc trc (thng l tch cc s la chn ca cc bc t 1 n i1) nh ta c th lu tr li c. Nu s la chn ny qu ln quy hoch ng
trong trng hp ny s thy bi. Hy tm cch chia bc v biu din li s la
chn. Mt trong nhng cch lm gim s la chn ca tt c cc bc trc l:
phi th t ho s la chn cc bc trc . V d bc 1 chn a, bc 2 chn b,
bc 3 chn c th cng ging nh bc 1 chn b, bc 2 chn c, bc 3 chn a. Chn
cch no th sau 3 bc ta cng c a, b, c. Nu lm c nh th ta gim t giai
tha thnh t hp ! S lng la chn s gim ng k c th lu tr.
Quay tr li bi ton, nu biu din 1 mc tiu b tiu dit l 1, v cha b tiu dit l 0
th mi s la chn ca cc bc t 1 n i-1 c th biu din bng 1 chui nh phn n bit.
Do n <= 15 nn chui nh phn n bit tng ng vi 1 s nguyn 15 bit. Do , ta c th s
dng 1 s nguyn biu din cc s la chn khc nhau ca cc bc t 1 n i-1. Nu gi
j l s nh phn biu din cc s la chn ca cc bc t 1 n i-1, th bc i ta c:
-
-

Nu chn mc tiu k tiu dit, th s ln bn ch ph thuc vo j (biu din nhng


mc tiu b tiu dit ri, ta xem ly v kh no bn k l tt nht).
Ta khng cn quan tm n th t cc mc tiu b tiu dit trong j.

V th, nu gi F[i-1][j] l s ln bn t nht tiu dit tt c cc mc tiu dit trong j


bc i-1 th s ln t nht tiu dit mc tiu <j+k> bc I l:
F[i][<j+k>] = min (F[i-1][j] + h(j, k)) vi mi j.
Trong :
-
-

<j+k> l php ton nh du mc tiu k b tiu dit trong j, hay t bit tng ng
vi k trong j bng 1. iu ny c ngha l tiu dit thm i tng k trong j. D nhin
l k cha b tiu dit trong j.
h(j, k) = s ln bn i tng k vi v kh tt nht trong j.

Gii thut quy hoch ng cho bi ny nh sau:


for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
F[i][j] = inf; //inf l s ln nht c th: 9999999
for(int i=1; i <= n; i++)
F[1][1 << (i-1)] = a[i]; //a[i] l ch s sc kho ca i
11/61

K thut phn tch v thit k gii thut

for(int i=2; i<=n; i++)


for (int j=1; j<=m; j++)
if (F[i-1][j] < inf)
for (int k=1; k<=n; k++)
if (!((1<<(k-1)) & j)) {
int h = 1;
for (int l=1; l<=n; l++) //tm v kh tt nht
if ((1<<(l-1)) & j)
h = max(h, C[l][k];
F[i][(1<<(k-1))|j] =
min(F[i][(1<<(k-1))|j],
F[i-1][j] + shot(h, k));
}
Trong gii thut trn,
-
-
-
-
-
-
-

inf l v cng. C th chn inf = tng cc A[i].


C[l][k] = Clk: sc cng ph ca v kh l i vi mc tiu k
shot(h, k): s ln bn k vi sc cng ph h v bng k/h.
hai vng for (j) v for (k) c th i ch cho nhau. Tch ca 2 s la chn chnh l s
lng nhau ca 2 vng lp.
php ton <j+k> c ci t bng php OR trn bit j | (1 <<(k-1)). 1 << (k-1) l 1 s
nguyn c ng 1 bt 1 nm v tr k (tnh t phi qua).
kim tra mc tiu k c trong j hay cha ta s dng php AND trn bit: 1<<(k-1) &
j.
Lnh if (F[i-1][j] < inf ) c dng tit kim thm 1 t thi gian v nu
F[i-1][j] = inf th ta khng cn cp nht F[i][(1<<(k-1))|j] lm g.

Trong bi ny ta thy rng khng phi quy hoch ng lc no cng quy hoch trn s
nguyn m cn c th quy hoch trn tp hp. ch s j trong F[i][j] v mt bn cht chnh l
mt tp hp. Ta xt tip mt bi tng t nh th.
1021 - Painful Bases: Cho mt c s base (2 <= base <= 16), mt s nguyn K (1<= K
<=20, K c cho trong h thp phn) v mt chui k t s biu din 1 s nguyn trong h
base-phn (nh phn nu base =2, thp phn nu base = 10, thp lc phn nu base =16, ).
Cc k t trong chui s u khc nhau. Tm s hon v cc phn t trong s sao cho to thnh
mt s trong h base-phn chia ht cho K.
V d:
base = 2, K = 2, s = 10 =>kt qu 1
base = 10, K = 2, s = 5681 =>kt qu 12
Tng t nh bi Agent 47, ta chia bi ton thnh n bc, mi bc la chn 1 s trong s
ghp vo kt qu ca cc bc trc to thnh mt s nguyn. Bc 1 c n cch chn.
Vi mi cch chn bc 2 c n-1 cch chn cho bc 2, Vi mi cch chn ca bc 1,
2, 3, , (i-1), bc i c (n-i+1) cch chn. Do s cch chn cho bc n s l n! Ta phi
tm cch biu din tt hn.
Gi s ta ang xt bc i, gi j l tp hp cc s c chn cc bc t 1 n (i-1).
Cn phi ch l: mi mt hon v trong j li cho ta mt s nguyn khc nhau, v th j c th
t. iu ny s lm s la chn bc i rt ln. Ta lm mt tnh th t ca j nh sau: v ta
quan tm n s d ca cc s c to ra t hon v chia cho K, nn ta phn cc hon v ca
j vo cc nhm t 0 n K-1 tng ng vi s d khi chia K. Nh th s cc hon v ca j l
ln nhng ta ch gom li cn c K trng hp khc nhau. K <= 20 nn c th chp nhn
c. Vi nhn xt ny, nu gi F[j][r] l s cc hon v cc s trong j chia cho K d r th:
12/61

K thut phn tch v thit k gii thut

F[<j+k>][mod] = tng F[j][r] vi mi j.


Trong , mod = (s[k]*base^(i-1) + r) % K do bc i, ta chn s s[k] ghp thm vo bn
tri mt trong cc hon v j (ta cng c th ghp thm vo bn phi, lc cng thc tnh
mod s khc i 1 cht). iu ny c ngha l nu cc hon v ca j to thnh s chia cho K d
r th khi ghp thm s[k] vo bn tri s to ra khi chia cho K d mod (nu ghp vo bn phi
s d s l mod = (r*base + s[k])%K).

Gii thut quy hoch ng cho bi ny c cho nh bn di:


memset(F, 0, sizeof(F));
for (int i = 1; i <= n; i++) {
int val = digit[i];
F[1 << (i-1)][val%K] = 1;
}
long long m = (1 << n) - 1;
long long b = 1;
for (int i = 2; i <= n; i++) {
b = (b*base)%K; //nguy hiem cn thn do trn s
for (int r = 0; r < K; r++)
for (long long j = 1; j <= m; j++) {
if (F[j][r] > 0 && num(j) == i-1) { //nguy hiem: cn kim
for (int k = 1; k <= n; k++) // tra s phn t ca j
if (!((1 << (k-1)) & j)) {
int mod = (digit[k]*b + r)%K;
F[j | (1 << (k-1))][mod] +=
F[j][r];
}
}
}
}
return F[m][0];
Khng ging nh bi Agent 47, thng tin v s bc i c lu trong F[i][j], Bi ny ta
khng lu i nn phi kim tra num(j) == i-1 vi num(j) l s bit 1 c trong j (tng ng s
phn t chn). C th hnh dung k thut quy hoch ng c p dng nh sau: u tin
j ch cha mt phn t (bc 1), bc 2 chn thm mt phn t na ghp vo j, n bc
n, j s cha n s 1 ng vi tt c cc phn t u c chn.

S hc ng d

3.1 Chia ht v chia c d


Chia ht: Cho s nguyn a v s nguyn dng b. Ta gi a chia ht cho b nu tn ti s
nguyn q sao cho a = q*b. q c gi l thng ca php chia. Trong trng hp ny ta gi
b l c s ca a v a l bi s ca b.
13/61

K thut phn tch v thit k gii thut

Chia c d: Cho s nguyn a v s nguyn dng b. Ta ni a chia cho b d r nu tn ti s


nguyn q sao cho a = q*b + r. r c gi l s d (0 r < b), q vn c gi l thng ca
php chia.
Ch :
- S d khng bao gi m.
- Php ton chia ly phn d trong cc ngn ng lp trnh (% trong C/C++, mod trong
PASCAL) khng quan tm n vic s b chia l s m. V th nu kt qu m ta
cng kt qu vi s chia. V d -7 % 3 = -1 nn s d l -1 + 3 = 2.
ng d: Cho hai s nguyn a v b, ta gi a v b ng d theo modulo m nu a b chia ht
cho n. K hiu: a b (mod n). a v b ng d theo modulo n cng c th hiu l s d khi
chia a cho n bng vi s d khi chia b cho m.
Mt s tnh cht ca ng d c th s dng gii cc bi ton. Nu gi % php chia ly
phn d:
(a + b) % MOD = a % MOD + b % MOD
(a - b) % MOD = a % MOD - b % MOD
(a * b) % MOD = a % MOD * b % MOD
an % MOD = (a % MOD)n
a s cc bi ton c kt qu qu ln thng c yu cu chia cho 1,000,000,007 ly phn
d.

3.2 S nguyn t
S p > 1 c gi l s nguyn t nu n ch c ng 2 c s dng l 1 v chnh n, v d:
2, 3, 5, 7, 11,
Ch :
-
-

1 khng phi l s nguyn t.


2 l s nguyn t nh nht.

Kim tra mt s p c phi l s nguyn t: gii thut n gin l ta ln lt th chia p cho i


chy t 2 -> sqrt(p). Nu p chia ht cho bt k 1 s no trong khong t 2 n sqrt(p) th p
khng phi l s nguyn t.
for (int = 2; i <= sqrt(p); i++)
if (p % i == 0)
return false;
return true;
Lit k cc s nguyn t t 2 n MAX: C th s dng sng Eratosthenes tm cc s
nguyn t trong khong t 2 n MAX. tng nh sau:
1. To mt danh sch cha cc s t 2 n MAX.
2. nh du tt c l s nguyn t.
3. Ln lt xt cc s p t 2 n sqrt(MAX), nu n c dnh du l s nguyn t
(u tin l 2, ln th 2 l 3, ln th 3 l 5, ), nh du xo tt c cc bi s ca p
trong danh sch.
Kt thc gii thut, cc s c dnh du l s nguyn t s l s nguyn t.
int prime[MAX] ;
14/61

K thut phn tch v thit k gii thut

for (int i = 2; i <= MAX; i++) {


prime[i] = true;
}
for (int p = 2; p*p <= MAX; p++)
if (prime[i])
for (int j = p*p; p < MAX; j += p)
prime[j] = false;
Nu ta c c cc s nguyn t t 2 n sqrt(p), vic kim tra tnh nguyn t ca p c th
thc hin nhanh hn bng cch th chia p cho cc s nguyn t .

3.3 Bi ton t-prime


Xem chi tit ti y (http://codeforces.com/problemset/problem/230/B).
Mt s c gi l t-prime nu n c ng 3 c s dng. Mt s nguyn dng s c 2
c s l 1 v chnh n. Ngoi 1 v chnh n, nu p c thm 1 c s nh hn sqrt(p) th chc
chn n s c 1 c khc. V th p c ng 3 c s nu nh n c 1 c nguyn t ng
bng sqrt(p).
Ni cch khc, p l t-prime nu n l bnh phng ca 1 s nguyn t.
Trong bi ton ny ta phi xt xem s x (1 <= x <= 1012) c phi l t-prime hay khng.
Nh phn tch trn, x phi = q2 v q l nguyn t. Ta cn tm tt c cc s nguyn t t 2
n sqrt(x). sqrt(x) ln nht l sqrt(1012) = 106. Dng sng Eratosthenes tm cc s nguyn t
t 2 n 106. Sau ta kim tra sqrt(x) c phi l s nguyn khng v sqrt(x) c phi l s
nguyn t khng.
#include <iostream>
#include <math.h>
using namespace std;
//230 B t-prime
#define MAXPRIME 1000001
int prime[MAXPRIME];
void erathosthenes() {
prime[0] = prime[1] = 0;
for (long long i = 2; i < MAXPRIME; i++)
prime[i] = 1;

for (long long i = 2; i*i < MAXPRIME; i++) {


if (prime[i])
for (long long j = i*i; j < MAXPRIME; j += i)
prime[j] = 0;
}

int main() {
long long n, x;
erathosthenes();
15/61

K thut phn tch v thit k gii thut

cin >> n;
for (int i = 0; i < n; i++) {
cin >> x;
long long q = sqrt(x);
if (q*q == x && prime[q])
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;

3.4 Phn tch mt s thnh tch cc tha s nguyn t


Mi s nguyn dng n u c th c phn tch duy nht thnh tch cc tha s nguyn t:
n = p1k1 * p2k2 * * pNkN vi p1, p2, , pN l cc s nguyn t, k1, k2, , kN l cc s
nguyn >= 0.
V d: 6 = 2*3, 5 = 5, 12 = 22*3
Phn tch 1 s nguyn ln thnh tch cc tha s nguyn t rt tn thi gian. Tuy nhin nu ta
bit cc s nguyn t t 2 n sqrt(n) ta c th nhanh chng tm ra cc tha s nguyn t
ca n v t c th tm c tt c cc c s ca n.
1054 - Efficient Pseudo Code. Xt bi ton tm tng cc c s ca nm nh sau: cho 2 s
nguyn c du 32 bit n v m (n >= 1 v m >= 0), tnh tng cc c ca nm. Chia tng s cho
1000,000,007 ly phn d.
Gi s n c phn tch thnh p1k1 * p2k2 * * pNkN, th:
nm = p1m*k1 * p2m*k2 * * pNm*kN
Tng cc c ca nm s l:
S = (p10 + p11 + + p1m*k1)* (p20 + p21 + + p2m*k1)* *(pN0 + pN1 + + pNm*kN)
Mi mt phn t sau khi nhn phn phi v phi ca S s l 1 c s ca nm.
Nh vy, tnh S trc ht ta phi tm cc pi v ki, sau tnh tch ca cc tng.
Tm pi v ki chnh l phn tch n thnh cc tha s nguyn t. Gi s cc s nguyn t t 2
n sqrt(n) c lu trong danh sch pp, ta phn tch n nh sau:
for (int i = 0; i < pp.size(); i++) {
int k = 0;
while (n%pp[i] == 0) {
n /= pp[i];
k++;
}
if (k > 0)
output (pp[i], k)
}
if (n > 1)
output (n, 1);
16/61

K thut phn tch v thit k gii thut

Dng if cui cng kim tra xem nu n cn st li 1 c nguyn t ln hn sqrt(n) khng. V


d n = 36, sqrt(36) = 6, vng for i s output ra (2, 2). Sau vng for n = 36/2/2 = 9, ta phi
output (9,1).
Vn k tip l tnh tng S(k) = (p0 + p1 + + pk) nh th no cho nhanh. Ta c th p
dng phng php tnh lu tha nhanh vo vic tnh tng ny. Bng cch chia bi ton cn
tnh thnh 2 bi ton con ging nhau, ta s tit kim c thi gian.
Nu k l s l th tng (p0 + p1 + + pk) c th chia thnh hai phn mi phn c (k+1)/2 s
hng: (p0 + p1 + + p(k+1)/2-1) + p(k+1)/2(p0 + p1 + + p(k+1)/2-1)
Vy nu k l s l th S(k) = S((k+1)/2 - 1)*(1 + p(k+1)/2) = S((k-1)/2)*(1 + p(k+1)/2).
Nu k l s chn, ta b bt phn t cui cng, phn cn li s l s chn, ni cch khc: nu k
chn,
S(k) = S(k-1) + pk

= pk + S((k-2)/2)* (1 + p(k)/2)
= pk + S((k-2)/2)* (1 + p(k+1)/2)

Trng hp suy bin, k = 0, S(0) = 1.


pk c th c tnh nhanh bng gii thut tnh lu tha nhanh nh phn 1.
long long mod_power(long long p, long long k) {
long long r = 1;
while (k > 0) {
if (k%2)
r = (r*p)%MOD;
k >>= 1;
p = (p*p)%MOD;
}
return r;
}
long long sum(long long p, long long k) {
if (!k) return 1;
long long temp = mod_power(p,(k+1)>>1) + 1);
if (k&1)
//k l, nn (k-1)/2 = k/2
return temp*sum(p, k >> 1)%MOD;
return (mod_power(p, k) +
temp*sum(p, (k-2)>>1))%MOD;
}
Ta cng c th ci tin 1 cht vic tnh ton S = p0 + p1 + + pk nhanh hn. n gin
vic phn tch ta b bt phn t p0 ra khi S s phn t trong tng = k.
Nu t S1 = + p1 + + pk th S = 1 + S1.
Ta s phn tch cch tnh S1 bng phng php lp. Lp lun tng t nh trn, nu k l s
chn:
S1(k)

= (p1 + p2 + + pk/2) + pk/2(p1 + p2 + + pk/2)


=S1(k/2)*(1+pk/2)

Nu k l s l
S1(k) = S1(k-1) + pk
Gi s ta ang c S1(i) th S1(2i) = S1(i)*(1 + pi) v
17/61

K thut phn tch v thit k gii thut

S(2i + 1) = S1(i)*(1 + pi) + p2i + 1 = S1(i)*(1 + pi) + p*(pi)^2


Bt u t S1(0) = 0, ta tm cch tnh S1(k) bng cch tng k vi php *2 hoc *2 v + 1. V
d nu k = 6, th t 0 -> 1 -> 3 -> 6.
Chui cc php bin i ny chnh l chui nh phn biu din k. Gi s k = 6 = 110.
u tin ta c i = 0, gp bt u tin l bt 1 ta tng i = 2*i + 1 = 1. K tip gp bt 1 na tng
i = 2*i + 1 = 3, bt cui cng l bt 0, ta tng i = 2*i = 6.
n y ta ngh ra cch tnh S1(k) t S1(0) ri phi khng. Nu cha th tip tc nh.
Gi s chui nh phn biu din k l bq bq-1 b1.
Khi to: S1 = 0; pi = 1;
for (int j = q; j >= 1; j--) {
S1 = S1*(1 + pi);
pi = pi*pi;
if (b[j] == 1) {
pi = pi*p;
S1 = S1 + pi;
}
}
tm chui bq bq-1 b1 ta p dng phng php i s thp phn thnh nh phn. Ton
b gii thut tnh S = p0 + p1 + + pk c trnh by nh sau:
long long sum(long long p, long long k) {
if (!k)
return 1;
int b[33], q = 0;
long long kk = k;
while (kk > 0) {
b[++q] = kk&1;
kk >>= 1;
}
long long S1 = 0, pi = 1;
for (int j = q; j >= 1; j--) {
S1 = S1*(1 + pi) % MOD;
pi = pi*pi % MOD;
if (b[j]) {
pi = pi*p % MOD;
S1 = (S1 + pi) % MOD;
}
}
return (S1 + 1) % MOD;
}
Ta c th p dng cch ny gii bi 1142 - Summing up Powers (II) trn Light Oj
(http://lightoj.com/volume_showproblem.php?problem=1142).

18/61

K thut phn tch v thit k gii thut

Nh th ta thng tin gii bi tng c s.


//Tm cc s nguyn t t 2 n sqrt(n) lu vo mng hay
vector pp
// sqrt(2^31-1) = 46340.95
#define MAXPRIME 46342
int prime[MAXPRIME];
vector<int> pp;
void erathosthenes() {
prime[0] = prime[1] = 0;
for (long long i = 2; i < MAXPRIME; i++)
prime[i] = 1;
for (long long i = 2; i*i < MAXPRIME; i++) {
if (prime[i])
for (long long j = i*i; j < MAXPRIME; j += i)
prime[j] = 0;
}
for (long long i = 2; i < MAXPRIME; i++)
if (prime[i])
pp.push_back(i);
}
//Phn tch n thnh cc s nguyn t v tnh tng
long long result = 1;
for (int i = 0; i < pp.size(); i++) {
int k = 0;
while (n%pp[i] == 0) {
n /= pp[i];
k++;
}
if (k > 0)
result = result*sum(pp[i], k*m) %MOD;
}
if (n > 1)
result = result*sum(n, m) % MOD;
return result;
Hy dng li ti y v chun b submit code ca bn.

19/61

K thut phn tch v thit k gii thut

Nu vn cha c bn c th tham kho on code sau:


#include <iostream>
#include <vector>
#include <string.h>
#include <math.h>
using namespace std;
//1054 - Efficient Pseudo Code
#define MAXPRIME 46342
#define MOD 1000000007
char prime[MAXPRIME];
vector<long long> pp;
void erathosthens() {
for (long long i = 2; i < MAXPRIME; i++)
prime[i] = 1;
for (long long i = 2; i*i < MAXPRIME; i++) {
if (prime[i]) {
for (long long j = i+i; j < MAXPRIME; j += i) {
prime[j] = 0;
}
}
}
for (long long i = 2; i < MAXPRIME; i++)
if (prime[i])
pp.push_back(i);
}
long long sum(long long p, long long k) {
if (!k)
return 1;
int b[34], q = 0;
long long kk = k;
while (kk > 0) {
b[++q] = kk&1;
kk >>= 1;
}
long long S1 = 0, pi = 1;
for (int j = q; j >= 1; j--) {
S1 = S1*(1 + pi) % MOD;
pi = pi*pi % MOD;
if (b[j]) {
pi = pi*p % MOD;
S1 = (S1 + pi) % MOD;
}
}
return (S1 + 1) % MOD;
}
long long process(long n, long long m) {
long long result = 1;
20/61

K thut phn tch v thit k gii thut

for (long long i = 0; i < pp.size(); i++) {


long long k = 0;
while (n % pp[i] == 0) {
k++;
n /= pp[i];
}
if (k > 0)
result = result*sum(pp[i], k*m) % MOD;
}
if (n > 1)
result = result*sum(n, m) % MOD;
}

return result;

int main()
{
long nCase, n, K, m;
cin >> nCase;
string s;
erathosthens();
for (long long no = 1; no <= nCase; no++) {
cin >> n >> m;
cout << "Case " << no << ": "
<< process(n, m) << endl;
}
return 0;
}

3.5 S d ca (a/b) % MOD


Trong cc tnh cht trong phn ng d pha trn khng c nhc n (a/b) % MOD. Ta s
xem xt vn ny.
Nu b v MOD nguyn t cng nhau (c s chung ln nht ca chng l 1), s tn ti 1 s
nguyn c sao cho b*c % MOD = 1. Ta gi c l s nghch o ca b theo modulo MOD v k
hiu b-1 = c. Cho trc b v MOD ta c th p dng gii thut Euclide m rng tm b-1
(s cp n gii thut ny sau).
Nh vy nu b-1 l nghch o ca b th (a/b) % MOD = a*b-1 % MOD.
nh l Fermat: Nu a v MOD nguyn t cng nhau th a (n) = 1 (mod n), hay a (n) chia n d
1 hay a (n) % n = 1.

Hm (n) l s cc s nguyn dng <=n v nguyn t cng nhau vi n. V d (9) = 6 v


cc s nguyn t cng nhau vi 9 l: 1, 2, 4, 5, 7, 8.
Nu p l s nguyn t th (p) = p-1.
Nh vy nu p l 1 s nguyn t v a < p th a nguyn t cng nhau vi p v nghch o ca a
theo modulo n l a (n)-1 = ap-2. Ta s ng dng tnh cht gii cc bi ton.

1067 Combinations (Light Oj) tnh t hp C(n, k) % MOD vi MOD = 1000003 v 0 <=
k <= n <= 1000000.

21/61

K thut phn tch v thit k gii thut

Bi ny c n kh ln nn ta khng th p dng quy hoch ng (theo tam gic PASCAL)


tnh C(n, k). Hn na ta cng khng th p dng cch tnh trc tip bng cc vng lp for.
Do 1000003 l s nguyn t nn ta c th d dng p dng cc php chia.
Ta bit rng:
!! =

!
! !

Nu t A = (n-1)! * k! th A nguyn t cng nhau vi MOD v MOD l s nguyn t nn


cc s nh MOD u nguyn t cng nhau vi MOD. A l tch ca cc s nguyn t cng
nhau vi MOD nn A cng nguyn t cng nhau vi MOD.
Nh th, nghch o ca A l AMOD - 2.
Vy C(k, n) % MOD = (n! * AMOD 2) % MOD.
p dng kt qu ny ta c gii thut nh sau:
-
-
-

Tnh trc cc F[i] = 1! (0 <= i <= MAX = 1000000)


Tnh nghch o ca A l A-1 = AMOD-2 (p dng gii thut tnh lu tha nhanh phn
trn)
Tnh n! * A-1 = F[n]*A-1.

Bn th submit xem sao.

22/61

K thut phn tch v thit k gii thut

Nu khng, xem gii thut y:


#include <iostream>
using namespace std;
//1067 - Combinations
#define MAX 1000001
#define MOD 1000003
long long F[MAX];
void fact() {
F[0] = 1;
for (int i = 1; i < MAX; i++)
F[i] = F[i-1]*i % MOD;
}
long long mod_power(long long n ,long long p) {
long long r = 1;
while (p > 0) {
if (p&1)
r = r*n % MOD;
p >>= 1;
n = n*n % MOD;
}
return r;
}
int main()
{

long nCase, n, k;
cin >> nCase;
fact();
for (long long no = 1; no <= nCase; no++) {
cin >> n >> k;
long long A = F[n-k]*F[k] % MOD;
long long r = F[n]*mod_power(A, MOD - 2) %MOD;
cout << "Case " << no << ": " << r << endl;
}
return 0;

23/61

K thut phn tch v thit k gii thut

Cy phn on (Segment Tree/Interval Tree)

4.1 Bi ton tnh trung bnh nhanh

Xt
bi
ton
1183
Computing
Fast
Average
trn
Light
Oj
(http://lightoj.com/volume_showproblem.php?problem=1183). Cho 1 mng s nguyn n
phn t 1 n 105. Ch s mng bt u t 0. u tin cc phn t u c gi tr 0. Bn phi
thc hin q (1 q 50000) thao tc thuc 1 trong 2 php ton sau y:
1. 1 i j v gn gi tr cc phn t t i n j bng v (0 v 10000).
2. 2 i j tnh gi tr trung bnh ca cc phn t t i n j.
Nu lm nh thng thng, c ngha l s dng vng lp t i n j gn hoc cng gi tr,
th ta s b time limit exceeded. Nhng bi ton dng ny s c gii quyt hiu qu nu s
dng mt cu trc d liu ph hp: Intertal Tree.
tng chnh ca interval tree l chia mng d liu thnh nhng on (interval), v t chc
cc on thnh mt cy phn cp. Mi nt qun l mt on t ch s left n right. Nt gc
qun l ton b mng, t ch s t 0 n n-1.
Mi khi thc hin thao tc trn mt on [i, j], v nt node ang qun l on ny, ta ch cn
thc hin lu tr hoc truy vn trn nt node m khng cn phi i n tng phn t t i n
j.

4.2 Ci t interval tree


Interval c th ci t kh n gin bng mt mng cc nt nodes. Quan h cha-con gia
cc nt v on qun l ca tng nt c ngm nh nh sau:
-
-
-
-
-
-

Thng tin ca nt i c lu trong phn t th i ca mng cc nt: nodes[i].


Nt gc l phn t 1 trong mng nodes.
Nt i c 2 con l nodes[2*i] v nodes[2*i + 1]
Nt gc qun l on t 0 n n-1 (hay t 1 n n tu theo mng d liu c t chc
nh th no. Trong bi ton tnh trung bnh ta cho nt gc qun l t on 0 n n-1)
Nu nt I qun l on t left n right th nt con tri 2*i qun l on t left n
mid v nt con phi 2*i+1 qun l on t mid+1 n right vi mid = (left+right)/2.
Nt l qun l 1 phn t duy nht ca mng d liu (left =right).

Ch : do ngm nh nh th nn ta khng cn phi lu tr cc con tr ch n con tri,


con phi hay nt cha ca mt nt. Ta cng khng cn phi lu tr on qun l ca mt nt.
Thng tin ca mt nt thng thng gm 2 thnh phn: thng tin ring v thng tin tng
hp ca c on. Khi thao tc trn mt nt, ta lu tr vo phn thng tin ring, cp nht
thng tin tng hp v lan truyn thng tin tng hp ln nt cha. Thng tin tng hp ca mt
nt lun phn nh thng tin ca ton b on m nt qun l.
struct NodeType {
thng tin ring
thng tin chung
};
NodeType nodes[MAX*4];
//MAX l kch thc ca mng d liu

24/61

K thut phn tch v thit k gii thut

Cc thao tc trn interval tree:


void init_tree(int node, int left, int right) {
//khi to chung cho 1 nt
if (left == right) {
//khi to nt l y
return;
}
//khi to nt trong y
int mid = (left + right)/2
init_tree(2*node, left, mid);
init_tree(2*node+1, mid+1, right);
//tng hp thng tin t 2 nt con y
}
a. Khi to
gi khi to cy ta gi: init_tree(1, 0, n-1)
b. Cp nht & truy vn
Interval tree hot ng theo c ch lazy update c ngha l ch cp nht khi cn. Khi cp
nht ni dung ton b on m nt ang qun l vi mt gi tr ging nhau, n ch cp nht
ni dung ny vo phn thng tin ring m khng i xung cp nht cc nt con ca n. y
chnh l mu cht ca vic tng tc ca interval tree. Nu ci t khng kho ch ny,
interval tree cn t hn s dng vng lp !
Nu ta dng vic cp nht ni dung ca mt on ti nt cha m khng i xung cc nt con,
chu th khi truy vn mt on do nt con qun l th th no ? Nt con hon ton khng hay
bit g v vic cp nht nt cha ca n c. C ch lazy update hot ng nh th ny: Khi
cp nht ni dung/truy vn thng tin mt nt con m nt cha ca n cn ang gi thng tin
ring (cha truyn xung) th ta thc hin vic lan truyn thng tin xung, trc khi cp
nht/truy vn. V th mi nt nn c 1 du hiu g bo l nt ang gi thng tin
cha lan truyn.

4.3 Gii bi tnh trung bnh nhanh


c c trung bnh ca on, ta cn phi c tng gi tr cc phn t trong on. S phn
t trong mt on d dng tnh c bng j i +1. V th thng tin tng hp ca mt nt l
tng cc phn t trong on nt qun l. Thng tin ring ca nt l gi tr c gn cho ton
on m nt qun l. Do gi tr v gn cho cc phn t >= 0, nn ta c th s dng lun thng
tin ring ny cho bit l nt c ang gi gi tr cha lan truyn xung hay khng. Nu v =
-1 chng hn, th nt khng gi gi tr cha lan truyn, ngc li n ang gi gi tr cha lan
truyn.
Khai bo:
#define MAX 100005
struct NodeType {
int value;
int sum;
};
NodeType nodes[MAX*4];

25/61

K thut phn tch v thit k gii thut

Khi to:
void init_tree(int node, int left, int right) {
nodes[node].value = -1; nodes[node].sum = 0;
if (left == right) {
return;
}
int mid = (left + right)/2;
init_tree(2*node, left, mid);
init_tree(2*node+1, mid+1, right);
}
Cp nht 1 on [u,v] vi gi tr val:
void update(int node, int left, int right,
int u, int v, int val) {
if (u > right || v < left)
return; //[u,v] nm ngoi on qun l ca node
if (u <= left && v >= right) {
nodes[node].value = val;
nodes[node].sum = (right-left+1)*val;
return;
}
/*y l trng hp cp nht mt on con ca on ang qun
l. Trc ht phi lan truyn gi tr cha cp nht ca n
(node) xung cc con ca n*/
int mid = (left+right)/2;
if (nodes[node].value != -1) {
int value = nodes[node].value;
nodes[2*node].value = value;
nodes[2*node].sum = (mid-left+1)*value;
nodes[2*node+1].value = value;
nodes[2*node+1].sum = (right-mid)*value;
nodes[node].value = -1; // lan truyn xong

}
update(2*node, left, mid, u, v, val);
update(2*node+1, mid+1, right, u, v, val);
//tng hp tng t 2 con
nodes[node].sum = nodes[2*node].sum +
nodes[2*node+1].sum;

26/61

K thut phn tch v thit k gii thut

Truy vn tng 1 on [u, v]:


int query(int node, int left, int right,
int u, int v) {
if (u > right || v < left)
return 0; //[u,v] nm ngoi on qun l ca node
if (u <= left && v >= right)
return nodes[node].sum;
/*y l trng hp truy vn mt on con ca on ang qun
l. Trc ht phi lan truyn gi tr cha cp nht ca n
(node) xung cc con ca n*/
int mid = (left+right)/2;
if (nodes[node].value != -1) {
int value = nodes[node].value;
nodes[2*node].value = value;
nodes[2*node].sum = (mid-left+1)*value;
nodes[2*node+1].value = value;
nodes[2*node+1].sum = (right-mid)*value;
nodes[node].value = -1; // lan truyn xong
}
return query(2*node, left, mid, u, v) +
query (2*node+1, mid+1, right, u, v);
}
X l kt qu:
Nu tng chia ht cho s phn t in tng. Nu khng, ta phi rt gn phn s. Tm c s
chung ln nht (USCLN) bng gii thut Euclide v chia c t v mu cho USCLN. Gii
thut Euclide tm USCLN c cho nh bn di.
int gcd(int a, int b) {
while (b) {
int r = a%b;
a = b;
b = r;
}
return a;
}
No cc bn th submit i nh !

27/61

K thut phn tch v thit k gii thut

Nu gp kh khn c th tham kho code mu:


//1183 - Computing Fast Average
#include <stdio.h>
#include <string.h>
#include <math.h>
#define MAX 100005
struct NodeType {
int value;
int sum;
};
NodeType nodes[MAX*4];
void init_tree(int node, int left, int right) {
nodes[node].value = -1; nodes[node].sum = 0;
if (left == right) {
return;
}
int mid = (left + right)/2;
init_tree(2*node, left, mid);
init_tree(2*node+1, mid+1, right);
}
void update(int node, int left, int right,
int u, int v, int val) {
if (u > right || v < left)
return; //[u,v] nm ngoi on qun l ca node
if (u <= left && v >= right) {
nodes[node].value = val;
nodes[node].sum = (right-left+1)*val;
return;
}
int mid = (left+right)/2;
if (nodes[node].value != -1) {
int value = nodes[node].value;
nodes[2*node].value = value;
nodes[2*node].sum = (mid-left+1)*value;
nodes[2*node+1].value = value;
nodes[2*node+1].sum = (right-mid)*value;
nodes[node].value = -1; // lan truyn xong
}
update(2*node, left, mid, u, v, val);
update(2*node+1, mid+1, right, u, v, val);
//tng hp tng t 2 con
nodes[node].sum = nodes[2*node].sum +
nodes[2*node+1].sum;
}
int query(int node, int left, int right,
int u, int v) {
28/61

K thut phn tch v thit k gii thut

if (u > right || v < left)


return 0; //[u,v] nm ngoi on qun l ca node
if (u <= left && v >= right)
return nodes[node].sum;
/*y l trng hp truy vn mt on con ca on ang qun
l. Trc ht phi lan truyn gi tr cha cp nht ca n
(node) xung cc con ca n*/
int mid = (left+right)/2;
if (nodes[node].value != -1) {
int value = nodes[node].value;
nodes[2*node].value = value;
nodes[2*node].sum = (mid-left+1)*value;
nodes[2*node+1].value = value;
nodes[2*node+1].sum = (right-mid)*value;
nodes[node].value = -1; // lan truyn xong

}
return query(2*node, left, mid, u, v) +
query (2*node+1, mid+1, right, u, v);

int gcd(int a, int b) {


while (b != 0) {
int r = a%b;
a = b;
b = r;
}
return a;
}
int main() {
int nCase, n, q, u, v, type, val;
scanf("%d", &nCase);
for (int no = 1; no <= nCase; no++) {
scanf("%d %d", &n, &q);
init_tree(1, 0, n-1);
printf("Case %d:\n", no);
for (int i = 1; i <= q; i++) {
scanf("%d", &type);
if (type == 1) {
scanf("%d %d %d", &u, &v, &val);
update(1, 0, n-1, u, v, val);
} else {
scanf("%d %d", &u, &v);
int r = query(1, 0, n-1, u, v);
int k = v - u + 1;
int g = gcd(r, k);
r /= g;
k /= g;
if (k > 1)
printf("%d/%d\n", r, k);
else
29/61

K thut phn tch v thit k gii thut

printf("%d\n", r);
}

}
return 0;

Ch :
-

S dng scanf, printf thay cho cin/cout tng tc c/ghi d liu. Nu khng
time limit exceeded !

4.4 Bi hc kinh nghim


-
-
-
-
-

p dng c k thut interval tree, ta phi m hnh bi ton v dng cp nht/truy


vn trn mt on.
Phn bit thng tin ring ca nt v thng tin tng hp.
Xc nh cch tnh thng tin tng hp ca 1 nt t thng tin tng hp ca cc nt con
Ch c ch lazy update: dng thao tc sm nht c th, hn ch i xung cc
on con khng cn thit.
S dng cc hm c/ghi d liu nhanh.

4.5 Cc bi tng t
-
-
-
-

1082 - Array Queries (Light Oj)


1135 - Count the Multiples of 3 (Light Oj)
1164 - Horrible Queries (Light Oj)

4.6 Cc bi nng cao

C kh nhiu bi cn phi phn tch tht k mi c th m hnh ho v Interval Tree. Ta ln


lt xem 1 s dng bi nh th.
1120 - Rectangle Union (Light Oj )
http://lightoj.com/volume_showproblem.php?problem=1120)

Cho mt s hnh ch nht c cnh song song vi cc trc to , ta cn tm tng din tch b
cc hnh ch nht che ph. Trong v d hnh bn di, tng din tch b che ph l 31 .
Mi hnh ch nht c m t bng 4 s nguyn x1, y1, x2, y2 trong (x1, y1) l gc di
tri cn (x2, y2) l gc trn phi. Trong hnh trn hnh ch nht vng c gc di tri l (0,
2), gc trn phi l (3, 6).
u vo: n hnh ch nht (1 n 30000), mi hnh l 4 s nguyn x1, y1, x2, y2 (0 x1, y1,
x2, y2 109, x1 < x2, y1 < y2).
30/61

K thut phn tch v thit k gii thut

u ra: tng din tch b ph.


Bi ny khng th p dng ngay interval tree c m phi phn tch v m hnh ho n v
cc thao tc trn on.
tm din tch b cc hnh ch nht bao ph ta chia khng gian bng cc cnh ng ca cc
hnh ch nht v tnh tng phn b bao ph c ngn cch bng cc cnh ng. Gi x1, x2,
, x2n l cc to ca cc cnh hnh ch nht c sp xp tng dn. Tng din tch b
ph = din tch b ph t x1 n x2 + din tch b ph t x2 n x3 + + din tch b ph t
x2n-1 n x2n. rng phn b gii hn bi xi v xi+1 l (xi+1 xi). Nu c thm c tng
chiu cao ca cc vng b ph (trong 1 phn c th c 1 hoc nhiu vng b ph), ta nhn vi
rng s c c din tch ca vng.

Nu gi ymin l to ca cnh thp nht v ymax l to cnh ngang cao nht trong tt c
cc hnh ch nht. Ta s qun l tng chiu cao ca cc vng b bao ph trong tng phn b
chia cch bng cc cnh ng. V d, trong hnh trn, phn u tin c tng chiu cao b bao
ph = 4 (chiu cao ca hnh ch nht vng), phn th hai c tng chiu cao = 5, phn th 3
c tng chiu cao = 6, Ta thy rng tng chiu cao trong tng phn vng s thay i. S
thay i ny l do khi chuyn vng, ta bt u 1 hnh ch nht mi, hoc kt thc mt hnh
ch nht c. Nu ta gp mt cnh l cnh bt u (cnh tri) ca hnh ch nht, ton b chiu
cao t y1 n y2 s b hnh ch nht ang xt bao ph. Ngc li, nu ta gp mt cnh phi
ca hnh ch nht, tng chiu cao b bao ph c th b gim cng c th khng (do mt c
th b nhiu hnh ch nht bao ph).
n y, bn on ra cch dng interval tree qun l vic bao ph ny cha?
Ta s dng mt interval tree qun l mt on t ymin n ymax (thc t ta nn qun l cc
t ymin n ymax-1, thay qun l v cc to ). u tin tt c cc u khng b bao ph
nn c gi tr bng 0.
Sau khi sp xp cc cnh ng theo th t tng dn, ta ln lt duyt qua cc cnh, mi khi
gp mt cnh bt u ta tng gi tr ca cc t y1 n y2 ln 1. Mi khi gp 1 cnh kt thc,
ta ta gim gi tr ca cc t y1 n y2 i 1. Sau mi thao tc tng hay gim ta phi cp nht
s b ph (c gi tr > 0) ca cc nt trong interval tree. m s b ph ta truy vn
trong on t ymin n ymax c bao nhiu b ph. on ny do nt gc qun l, nn ta ch
cn ly thng tin tng hp ca nt gc l .
Tm li bi ton ny s c m hnh ho v cc thao tc trn interval tree nh sau:
-

Khi to, cc t ymin n ymax c gi tr 0.


31/61

K thut phn tch v thit k gii thut

Tng hoc gim gi tr ca cc trong mt on.

mi nt, thng tin ring l gi tr tng hay gim (+1/-1), thng tin tng hp l s cc c
gi tr > 0.
Khai bo
//10^9
#define MAX 10000000001
struct NodeType {
int value;
int sum;
};
NodeType nodes[MAX*4];
Khi to:
value = 0; sum = 0
Tng 1 on:
void increase(int node, int left, int right,
int u, int v) {
if (u > right || v < left)
return; //[u,v] nm ngoi on qun l ca node
if (u <= left && v >= right) {
nodes[node].value++;
nodes[node].sum = left - right + 1;
return;
}
increase(2*node, left, mid, u, v);
increase(2*node+1, mid+1, right, u, v);
//tng hp tng t 2 con
nodes[node].sum = nodes[2*node].sum +
nodes[2*node+1].sum;
}

32/61

K thut phn tch v thit k gii thut

Gim 1 on:
void decrease(int node, int left, int right,
int u, int v) {
if (u > right || v < left)
return; //[u,v] nm ngoi on qun l ca node
if (u <= left && v >= right) {
nodes[node].value--; //1 on ch c th >= 0
if (nodes[node].value == 0)
if (left != right)
nodes[node].sum = nodes[2*node].sum +
nodes[2*node+1].sum;
else
nodes[node].sum = 0;
return;
}
//khng cn lan truyn
decrease(2*node, left, mid, u, v);
decrease(2*node+1, mid+1, right, u, v);
//tng hp tng t 2 con
nodes[node].sum = nodes[2*node].sum +
nodes[2*node+1].sum;
}
Tuy nhin do (0 x1, y1, x2, y2 109) nn nu qun l trc tip tng t ymin n ymax, s tn
kh nhiu b nh v thi gian. Ta c th gim s trong on t 109 xung cn 30,000*2 =
60,000 khong thi (s hnh ch nht n 30,000 nn c 2*n cnh ngang => s khong = 2*n
- 1). Mi khong c gii hn bng 2 gi tr ymin v ymax. Trong v d bn di, ta c 3
hnh ch nht nn c 6 cnh ngang v to thnh 5 khong. Mi khong by gi ng vai tr
nh 1 phn t trong mng d liu trong bi ton Fast Average.
Phng php ny gi l ri rc ho d liu. qun l cc khong ta ch cn mt mng lu
cc cao tng dn, horizontals. Trong v d trn, nu tnh d di ln ta lu: 1, 2, 3, 4, 6 v
7 tng ng vi 5 khong. Interval tree qun l on t ymin n ymax nh sau:
5
4
3
2
1

33/61

K thut phn tch v thit k gii thut

Khai bo:
//2*30000
#define MAX 60001
struct NodeType {
int value;
long long sum;
long long ymin, ymax;
};
NodeType nodes[MAX*4];
long long height[MAX];
struct Rectangle {
long long x1, y1, x2, y2;
};
//Danh sch cc hnh ch nht
Rectangle rects[30000];
struct Vert {
long long x;
bool begin;
int id;
};
//Cc cnh ng
Vert verticals[MAX];
long long horizontals[MAX];
Khi to:
Vi mi nt ta lu li khong ymin v ymax m n qun l. Ch khong [ymin, ymax]
tng ng vi mt on d liu no trong mng d liu. Trong bi gii ny, horizontal c
ch s tnh t 0, ch s nt trn interval tree tnh t 1 nn khong i c ymin = horizontal[left1] v ymax = horizontal[left].
void init_tree(int node, int left, int right) {
nodes[node].value = 0; nodes[node].sum = 0;
if (left == right) {
nodes[node].ymin = horizontals[left-1];
nodes[node].ymax = horizontals[left];
return;
}
int mid = (left + right)/2;
init_tree(2*node, left, mid);
init_tree(2*node+1, mid+1, right);

nodes[node].ymin = nodes[2*node].ymin;
nodes[node].ymax = nodes[2*node+1].ymax;

34/61

K thut phn tch v thit k gii thut

Tng 1 on:
Trong cc hm tng/gim, ta s dng ymin, ymax xc nh khong qun l nt thay v
on trong mng d liu. Khi tng mt on bao ph hon ton khong ca mt nt, chc
chn khong ny b ph t nht 1 hnh ch nht nn ta khng cn i xung cc nt con ca
n. Cc con ca n s c cp nht da vo c ch lazy update ngha l ch cp nht khi
ta cp nht/truy vn con/chu ca n.
void increase(int node, int left, int right, int u, int v) {
if (u >= nodes[node].ymax || v <= nodes[node].ymin)
return; //[u,v] nm ngoi on qun l ca node
if (u <= nodes[node].ymin && v >= nodes[node].ymax) {
nodes[node].value++;
nodes[node].sum = nodes[node].ymax - nodes[node].ymin;
return;
}
int mid = (left + right)/2;
increase(2*node, left, mid, u, v);
increase(2*node+1, mid+1, right, u, v);

//tng hp tng t 2 con


if (nodes[node].value == 0)
nodes[node].sum = nodes[2*node].sum +
nodes[2*node+1].sum;

Gim 1 on:
Khi gi tr ca mt on b gim v 0, s b ph ca khong ny ph thuc vo 2 khong
ca 2 con ca n. Nu n l nt l, s b ph chc chn s l 0.
void decrease(int node, int left, int right, int u, int v) {
if (u >= nodes[node].ymax || v <= nodes[node].ymin)
return; //[u,v] nm ngoi on qun l ca node
if (u <= nodes[node].ymin && v >= nodes[node].ymax) {
nodes[node].value--; //value ca 1 on ch c th >= 0
if (nodes[node].value == 0) {
if (left != right)
nodes[node].sum = nodes[2*node].sum +
nodes[2*node+1].sum;
else
nodes[node].sum = 0;
}
return;
}
int mid = (left +right)/2;
decrease(2*node, left, mid, u, v);
decrease(2*node+1, mid+1, right, u, v);
//tng hp tng t 2 con
if (nodes[node].value == 0)
nodes[node].sum = nodes[2*node].sum +
nodes[2*node+1].sum;
}
35/61

K thut phn tch v thit k gii thut

Bi ton ny c 2 tnh cht c bit lm n d:


-

Gi tr ca mt nt khng bao gi m v ta lun tng 1 on (khi gp cnh bt u ca


1 hnh ch nht) trc khi gim gi tr ca n (khi gp cnh kt thc ca cng hnh
ch nht)
1 ch cn b ph t nht bi 1 hnh ch nht l c tnh. Trong mt s bi ton m
rng khc, ta cn phi m s b ph t nht k hnh ch nht nh trong bi 1204 Weird Advertisement. i vi cc bi nh th, mi khi tng/gim mt on ta
khng th dng ngay c m phi tip tc i xung tng hp s b ph trong
cc con ca n.

Nhim v cn li ca chng ta sp xp cc cnh ng theo th t tng dn v to cc khong


t cc cnh ngang.
Sp xp cnh ng v to cc khong t cc cnh ngang. Cc cnh c tung bng nhau ch
gi li 1 gi tr.
bool my_compare(const Vert& a, const Vert& b) {
return a.x < b.x;
}
int create_interval(int n) {
//Cnh ngang <y, id-rect> ch s ca hnh ch nht
//dng cp nht t to sang ch s khong
static long long ys[MAX];
for (int i = 0; i < n; i++) {
verticals[2*i].x = rects[i].x1;
verticals[2*i].begin = true;
verticals[2*i].id = i;
verticals[2*i+1].x = rects[i].x2;
verticals[2*i+1].begin = false;
verticals[2*i+1].id = i;
ys[2*i] = rects[i].y1;
ys[2*i+1] = rects[i].y2;
}
sort(verticals, verticals + 2*n, my_compare);
sort(ys, ys + 2*n);
//unique
int k = 0; int y = -1;
for (int i = 0; i < 2*n; i++) {
if (y != ys[i]) {
horizontals[k] = ys[i];
y = ys[i];
k++;
}
}
return k-1;
}
36/61

K thut phn tch v thit k gii thut

Chng trnh mu:


//1120 - Rectangle Union
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <iostream>
#include <map>
using namespace std;
//2*30000
#define MAX 60001
struct NodeType {
int value;
long long sum;
long long ymin, ymax;
};
NodeType nodes[MAX*4];
long long height[MAX];
struct Rectangle {
long long x1, y1, x2, y2;
};
//Danh sch cc hnh ch nht
Rectangle rects[30000];
struct Vert {
long long x;
bool begin;
int id;
};
//Cc cnh ng
Vert verticals[MAX];
long long horizontals[MAX];
bool my_compare(const Vert& a, const Vert& b) {
return a.x < b.x;
}
int create_interval(int n) {
//Cnh ngang <y, id-rect> ch s ca hnh ch nht
//dng cp nht t to sang ch s khong
static long long ys[MAX];
for (int i = 0; i < n; i++) {
verticals[2*i].x = rects[i].x1;
verticals[2*i].begin = true;
verticals[2*i].id = i;
37/61

K thut phn tch v thit k gii thut

verticals[2*i+1].x = rects[i].x2;
verticals[2*i+1].begin = false;
verticals[2*i+1].id = i;
ys[2*i] = rects[i].y1;
ys[2*i+1] = rects[i].y2;
}
sort(verticals, verticals + 2*n, my_compare);
sort(ys, ys + 2*n);
//unique
int k = 0; int y = -1;
for (int i = 0; i < 2*n; i++) {
if (y != ys[i]) {
horizontals[k] = ys[i];
y = ys[i];
k++;
}
}
return k-1;
}
void init_tree(int node, int left, int right) {
nodes[node].value = 0; nodes[node].sum = 0;
if (left == right) {
nodes[node].ymin = horizontals[left-1];
nodes[node].ymax = horizontals[left];
return;
}
int mid = (left + right)/2;
init_tree(2*node, left, mid);
init_tree(2*node+1, mid+1, right);

nodes[node].ymin = nodes[2*node].ymin;
nodes[node].ymax = nodes[2*node+1].ymax;

void increase(int node, int left, int right, int u, int v) {


if (u >= nodes[node].ymax || v <= nodes[node].ymin)
return; //[u,v] nm ngoi on qun l ca node
if (u <= nodes[node].ymin && v >= nodes[node].ymax) {
nodes[node].value++;
nodes[node].sum = nodes[node].ymax - nodes[node].ymin;
return;
}
int mid = (left + right)/2;
increase(2*node, left, mid, u, v);
increase(2*node+1, mid+1, right, u, v);
//tng hp tng t 2 con
if (nodes[node].value == 0)
nodes[node].sum = nodes[2*node].sum +
38/61

K thut phn tch v thit k gii thut

nodes[2*node+1].sum;
}
void decrease(int node, int left, int right, int u, int v) {
if (u >= nodes[node].ymax || v <= nodes[node].ymin)
return; //[u,v] nm ngoi on qun l ca node
if (u <= nodes[node].ymin && v >= nodes[node].ymax) {
nodes[node].value--; //value ca 1 on ch c th >= 0
if (nodes[node].value == 0) {
if (left != right)
nodes[node].sum = nodes[2*node].sum +
nodes[2*node+1].sum;
else
nodes[node].sum = 0;
}
return;
}
int mid = (left +right)/2;
decrease(2*node, left, mid, u, v);
decrease(2*node+1, mid+1, right, u, v);
//tng hp tng t 2 con
if (nodes[node].value == 0)
nodes[node].sum = nodes[2*node].sum +
nodes[2*node+1].sum;
}
int main() {
int nCase, n;
scanf("%d", &nCase);
for (int no = 1; no <= nCase; no++) {
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%lld %lld %lld %lld",
&rects[i].x1, &rects[i].y1,
&rects[i].x2, &rects[i].y2);
int k = create_interval(n);
//cout << "k = " << k << endl;
init_tree(1, 1, k);
long long result = 0ll;
for (int i = 0; i < 2*n - 1; i++) {
int id = verticals[i].id;
if (verticals[i].begin) {
increase(1, 1, k, rects[id].y1, rects[id].y2);
} else {
decrease(1, 1, k, rects[id].y1, rects[id].y2);
}
result += nodes[1].sum*
(verticals[i+1].x - verticals[i].x);
}
39/61

K thut phn tch v thit k gii thut

printf("Case %d: %lld\n", no, result);


}
return 0;
}
Bn cng c th p dng cch tng t gii bi 1204 - Weird Advertisement (Light Oj).
1204 - Weird Advertisement (Light Oj)
2DPlaneLand is a land just like a huge 2D plane. The range of X axis is 0 to 109 and the
range of Y axis is also 0 to 109. People built houses only in integer co-ordinates and there
is exactly one house in each integer co-ordinate.
Now UseAndSmile Soap Company is launching a new soap. That's why they want to
advertise this product as much as possible. So, they selected n persons for this task. Each
person will be given a rectangular region. He will advertise the product to all the houses
that lie in his region. Each rectangular region is identified by 4 integers x1, y1, x2 and y2.
That means this person will advertise in all the houses whose x co-ordinate is between x1
and x2 (inclusive) and y co-ordinate is between y1 and y2 (inclusive).
Now after a while they realized that some houses are being advertised by more than one
person. So, they want to find the number of houses that are advertised by at least k
persons. Since you are one of the best programmers in the city; they asked you to solve
this problem.
Input
Input starts with an integer T ( 13), denoting the number of test cases.
Each case starts with a line containing two integers n (1 n 30000), k (1 k 10).
Each of the next n lines will contain four integers x1, y1, x2, y2 (0 x1, y1, x2, y2 109, x1
< x2, y1 < y2) denoting a rectangular region for a person.
Output
For each case, print the case number and the total number of houses that are advertised by
at least k people.
Sample Input
Output for Sample Input
2
Case 1: 27
21
Case 2: 8
0044
1125
22
0044
1125
Note
Dataset is huge. Use faster i/o methods.
Bi ny khc vi bi Rectangle Union 2 im chnh:
-
-

Cch tnh s nh trong mt vng ch nht khc vi din tch ca hnh ch nht.
Ta phi m s nh c qung co t nht k ln. k c th ln hn 1.
40/61

K thut phn tch v thit k gii thut

im khc bit u tin c th gii quyt bng cch di chuyn cc cn nh t giao im n


tm ca cc v ni rng hnh ch nht thm 1 n v cho c chiu rng v chiu cao.

i vi im khc bit th hai, khi mt on b ph bng mt hnh ch nht nu s lng


hnh ch nht b ph cn nh hn K, ta khng th tnh tng s b ph ngay m phi i
xung tm cc b ph t cc nt con ca n. Qu trnh i xung ny s dng li khi gp 1
nt l hoc mt on b ph nhiu hn k hnh ch nht.
Tng mt on: ta phi truyn thm 1 tham s parent cho bit tng s hnh ch nht
ph ln on ny (tnh t nt gc)
void increase(int node, int left, int right,
int u, int v, int parent) {
if (u >= nodes[node].ymax || v <= nodes[node].ymin)
return; //[u,v] nm ngoi on qun l ca node
if (u <= nodes[node].ymin && v >= nodes[node].ymax) {
nodes[node].value++;
//m s nh v kt thc
count(node, left, right, parent);
return;
}
int mid = (left + right)/2;
increase(2*node, left, mid, u, v,
parent + nodes[node].value);
increase(2*node+1, mid+1, right, u, v,
parent + nodes[node].value);

//tng hp tng t 2 con


if (parent + nodes[node].value < k)
nodes[node].sum = nodes[2*node].sum +
nodes[2*node+1].sum;

41/61

K thut phn tch v thit k gii thut

Gim mt on:
void decrease(int node, int left, int right,
int u, int v, int parent) {
if (u >= nodes[node].ymax || v <= nodes[node].ymin)
return; //[u,v] nm ngoi on qun l ca node
if (u <= nodes[node].ymin && v >= nodes[node].ymax) {
nodes[node].value--;
//m s nh v kt thc
count(node, left, right, parent);
return;
}
int mid = (left + right)/2;
decrease(2*node, left, mid, u, v,
parent + nodes[node].value);
decrease(2*node+1, mid+1, right, u, v,
parent + nodes[node].value);

//tng hp tng t 2 con


if (parent + nodes[node].value < k)
nodes[node].sum = nodes[2*node].sum +
nodes[2*node+1].sum;

m s nh ca mt on v cp nht vo bin tng hp sum:


void count(int node, int left, int right, int parent) {
if (parent + nodes[node].value >= k) {
nodes[node].sum = nodes[node].ymax - nodes[node].ymin;
return;
}
if (left == right) {
nodes[node].sum = 0;
return;
}
int mid = (left + right)/2;
//tng hp tng t 2 con
count(2*node, left, mid, parent + nodes[node].value);
count(2*node+1, mid+1, right,
parent + nodes[node].value);
nodes[node].sum = nodes[2*node].sum +
nodes[2*node+1].sum;
}
Bi k tip theo y s dng interval tree tng tc cho k thut quy hoch ng.
1415 - Save the Trees (Light Oj)
1 hng cy c nh s t 1 n n (n 2*105). mi cy thuc v 1 loi type[i] v c 1 chiu
cao height[i]. tnh gi tr ca ton b hng cy trc ht ta gom cc cy cnh nhau
thnh cc nhm. Loi ca cc cy trong cng nhm phi khc nhau. Gi tr ca mt nhm
bng chiu cao ca cy cao nht. Gi tr ca hng cy bng tng gi tr ca cc nhm. Vi
42/61

K thut phn tch v thit k gii thut

mi cch gom nhm khc nhau, ta c tng gi tr ca hng cy cng khc nhau. Nhim v
ca bn l tm gi thp nht.
V d: hng 5 cy nh bn di c gi thp nht l 26.
5
3
2
1
2
3

11
13
12
9
13

V d: hng 5 cy nh bn di c gi thp nht l 26.


Trc ht, ta th s dng k thut quy hoch ng phn tch bi ny. Ta chia bi ton
thnh n bc, mi bc ta xt 1 cy. Nu gi F[j] l gi thp nht ca cc cy t 1 n j,
bc i, ta xem xt cy th i. Ta c th gom cy i vo mt trong cc nhm (j, j+1, , i). Gi
Left[i] l cy xa nht v pha tri m ta c th gom n vo cng nhm vi cy i, ta c:
F[i] = min{F[j-1] + max-height(j, i)}
vi j chy t Left[i] n i v max-height(j, i) l chiu cao ca cy cao nht t j n i.
Gii thut quy hoch ng cho bi ny kh n gin:
for (int i = 1; i <= n; i++) {
F[i] = inf; int h = 0;
for (int j = left[i]; j <= i; j++) {
h = max(h, height[j]);
F[i] = min(F[i], F[j-1] + h);
}
}
tnh Left[i], ta c th s dng k thut quy hoch ng.
Left[i] l v tr gn i nht trong 2 v tr: Left[i-1] v v tr ca cy sau cng c cng loi vi
cy i hay:
Left[i] = max(Left[i-1] + loc[type[i]] +1);
trong loc[type[i]] l v tr ca cy sau cng c cng loi vi i.
void compute_left(int n) {
static int loc[MAX];
for (int i = 0; i <= n; i++)
loc[i] = 0;
Left[0] = 1;
for (int i = 1; i <= n; i++) {
Left[i] = max(Left[i-1], loc[type[i]]);
loc[type[i]] = i;
}
}
Tuy nhin ta khng th dng k thut quy hoch ng gii bi ny v n qu ln (n
2*105) v c n 2 vng lp lng nhau. S dng interval tree c th lm gim thi gian
tnh ton ca vng lp j.
M hnh ho bi ton ny v interval tng i phc tp. Ta th phn tch nh. Cng thc
tnh F[i] l:
43/61

K thut phn tch v thit k gii thut

F[i] = min{F[j-1] + max-height(j, i)}


t f[j] = F[j-1] v h[j] = max-height(j, i), ta c:
F[i] = min {f[j] + h[j]} vi mi left[i] j i.
Ta s dng 1 interval tree qun l 1 on t 1 n n. Mi phn t j lu f[j] + h[j]. tm
F[i] ta truy vn khong t left[i] n i ly gi thp nht. Mi khi thm mt cy mi, ta a
i vo interval tree v cp nht h[j] ca tt c cc phn t c h[j] height[i]. on cc phn t
cn cp nht h[j] l t before[i] n i vi before[i] l v tr ngay sau cy c chiu cao cao
hn i.
Nt node trong interval tree qun l cc cy t left n right, thng tin ring ca nt h[j].
Thng tin tng hp bao gm min_fh lu gi tr nh nht ca f[j] + h[j] vi tt c cc j trong
on node qun l v min_f lu gi tr nh nht ca f[j].
Khai bo:
#define MAX 200001
struct NodeType {
int h;
long min_fh;
long min_f;
};
NodeType nodes[MAX*4];
Khi to:
void init_tree(int node, int left, int right) {
nodes[node].h = 0; nodes[node].min_fh = 0;
min_f = 0;
if (left == right) {
return;
}
int mid = (left + right)/2;
init_tree(2*node, left, mid);
init_tree(2*node+1, mid+1, right);
}
Lan truyn
void propage(int node) {
if (nodes[node].h > 0) {
int mid = (left+right)/2;
int h = nodes[node].h;
nodes[2*node].h = h;
nodes[2*node].min_fh = nodes[2*node].min_f + h;

nodes[2*node+!].h = h;
nodes[2*node+1].min_fh =
nodes[2*node+1].min_f + h;
nodes[node].h= 0; // lan truyn xong

}
Tng hp
44/61

K thut phn tch v thit k gii thut

void synthesize(int node) {


nodes[node].min_fh = min(nodes[2*node]. min_fh,
nodes[2*node+1]. min_fh);
nodes[node].min_f = min(nodes[2*node].min_f,
nodes[2*node+1].min_f);
}

45/61

K thut phn tch v thit k gii thut

Thm cy i vo interval tree


void insert(int node, int left, int right, int i) {
if (u > right || v < left)
return; //[u,v] nm ngoi on qun l ca node
if (left == right) {
nodes[node].h = height[i];
nodes[node].min_fh = height[i];
nodes[node].min_f = F[i-1];
return;
}
propagate(node);
int mid = (left+right)/2;
if (i <= mid)
insert(2*node, left, mid, i);
else
insert(2*node+1, mid+1, right, i);
//tng hp tng t 2 con
synthesize(node);
}
Cp nht h[j] ca on [u, v]
Do ta lun cp nht cc on c h[j] nh hn gi tr cp nht h nn ta ch cn gn h[j] = h cho
c 1 on.
void update(int node, int left, int right,
int u, int v, int h) {
if (u > right || v < left)
return; //[u,v] nm ngoi on qun l ca node
if (u <= left && v >= right) {
nodes[node].h = h;
nodes[node].min_fh = nodes[node].min_f + h;
return;
}
propagate(node);
int mid = (left+right)/2;
update(2*node, left, mid, u, v, h);
update(2*node+1, mid+1, right, u, v, h);
//tng hp tng t 2 con
synthesize(node);
}

46/61

K thut phn tch v thit k gii thut

Truy vn tng 1 on [u, v]:


long long query(int node, int left, int right,
int u, int v) {
if (u > right || v < left)
return 0; //[u,v] nm ngoi on qun l ca node
if (u <= left && v >= right)
return nodes[node].min_fh;
propagate(node);
int mid = (left+right)/2;
return query(2*node, left, mid, u, v) +
query(2*node+1, mid+1, right, u, v);
}
Tnh ton before[i]
tnh before[i] ta s dng 1 stack lu v tr ca cc cy. Vi mi cy i, ta ln lt loi b
cc phn t trn nh stack c chiu cao thp hn chiu cao ca i. before[i] = v tr ca cy
trn nh stack + 1.
void compute_before (int n) {
static int stack[MAX];
int top = 0;
stack[top++] = 0;
for (int i = 1; i <= n; i++) {
while (top > 0 && height[top] <= height[i])
top--;
before[i] = stack[top] + 1;
stack[++top] = i;
}

47/61

K thut phn tch v thit k gii thut

Hm main()
int main() {
int nCase, n;
scanf("%d", &nCase);
for (int no = 1; no <= nCase; no++) {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d %d", &type[i], &height[i]);
init_tree(1, 1, n);
compute_left(n);
compute_before(n);
F[0] = 0;
for (int i = 1; i <= n; i++) {
insert(1, 1, n, i);
update(1, 1, n, Before[i], i, height[i]);
F[i] = query(1, 1, n, Left[i], i);
}
printf("Case %d: %lld\n", no, F[n]);
}
return 0;
}
No ta cng submit.

Gii tch v hnh hc

C rt nhiu bi ton thay v gii bng cch lp v tm kim, ta c th gii c n bng cch
p dng cc kt qu ca ton.

5.1 Bi ton khong cch ngn nht

Xt bi ton 1146 - Closest Distance (Light Oj) nh sau: mt ngi i t A n B v ngi


kia i t C n D. Tc di chuyn ca hai ngi t l thun vi chiu di ca on ng
ca h. Tnh khong cch ngn nht gia 2 ngi trn ng i.

Bi ny c xp trong nhm tm kim tam phn (Ternary Search), tuy nhin ta c th gii
bi ny bng cch tm cc tr ca mt hm 1 bin. tm cc tr ta ly o hm v gii
phng trnh o hm = 0. So snh gi tr ca hm ti 2 im cc bin v gi tr ti im c
o hm = 0.
Gi xA, yA, xB, yB, xC, yC, xD, yD l to ca cc im A, B, C v D. Ta c phng
trnh chuyn ng ca ngi th nht theo thi gian t nh sau:
= ( ) +
= ( ) +
Tng t phng trnh chuyn ng ca ngi th 2 l:
48/61

K thut phn tch v thit k gii thut

= ( ) +
= ( ) +
Bnh phng khong cch gia hai ngi theo t:
() = ) + ( ) !
+ ) + ( ) !
tm khong cch nh nht ta o hm d(t) theo t v gii phng trnh d(t) = 0 ta tm c
t*. Sau so snh 3 khong cch (A, C), (B, D) v d(t*) tm khong cch ln nht.
Code chng trnh mu:
#include <iostream>
#include <string.h>
#include <math.h>
using namespace std;
double xA, xB, xC, xD, yA, yB, yC, yD;
double pow2(double x) {
return x*x;
}
double process() {
double deltaX = xB - xA - xD + xC;
double deltaY = yB - yA - yD + yC;
double dx = xA - xC;
double dy = yA - yC;
double dist1 = sqrt(pow2(xA - xC) + pow2(yA - yC));
double dist2 = sqrt(pow2(xB - xD) + pow2(yB - yD));
double dist0;
if (deltaX*deltaX + deltaY*deltaY == 0)
dist0 = -1;
else {
double t = -(deltaX * dx + deltaY * dy)/
(deltaX*deltaX + deltaY*deltaY);
if (t < 0 || t > 1)
dist0 = -1;
else
dist0 = sqrt(pow2(deltaX*t + dx) +
pow2(deltaY*t + dy));
}
if (dist0 < 0)
return std::min(dist1, dist2);
return std::min(dist1, std::min(dist2, dist0));

}
int main() {
int nCase, n;
cin >> nCase;
cout.precision(12);
for (int no = 1; no <= nCase; no++) {
cin >> xA >> yA >> xB >> yB >> xC >> yC >> xD >> yD;
cout << "Case " << no << ": " << process() << endl;
}
return 0;
}
49/61

K thut phn tch v thit k gii thut

5.2 Bi tng t
-

1240 - Point Segment Distance (3D)

5.3 Olympics (1056 Light Oj)

Sn vn ng ca mt t th vn hi c hnh dng l hnh ch v hai cung trn thuc cng 1


ng trn (xem hnh). Tnh chiu di (length) v chiu rng ca hnh ch nht trn nu bit
t l gia chiu di v chiu rng v chu vi ca sn vn ng l 400m.
V d:
Sample Input
Output for Sample Input
2
Case 1: 117.1858168 78.12387792
3 : 2
Case 2: 107.29095604 85.8327648
5 : 4
Bi ny c xp nm trong nhm tm kim nh phn. Tuy nhin ta c th bi ny mt cch
nhanh chng bng cch p dng cc kin thc v hnh hc v lng gic.

D
2

Nu gi gc ACB = , p dng tng ca 3 gc trong tam gic bng 180o, ta d dng suy ra
gc AOB = 2.
Na chu vi ca sn vn ng = AD + OA* 2 = AD + AC*.
Mt khc AC = BD/cos() = AD/cos(). Thay vo trn ta
AD + AD*/cos() = 400/2 = 200
Suy ra:
Chiu di = AD = 200(1 + /cos())
Chiu rng = chiu di/t l
tm , ta xt:
tan() = chiu rng/chiu di
=> = atan(chiu rng/chiu di).
n y th xem nh bi ton gii xong.
No cc bn cng submit nh!
Code mu:
50/61

K thut phn tch v thit k gii thut

//1056 - Olympics
#include <iostream>
#include <math.h>
using namespace std;
void solve(int l, int w) {
double alpha = atan2(w, l);
double length = 200.0/(1.0 + alpha/cos(alpha));
double width = length*w/l;
cout << length << ' ' << width << endl;
}
int main() {
int nCase, w, l;
char c;
cin >> nCase;
cout.precision(9);
for (int no = 1; no <= nCase; no++) {
cin >> l;
cin >> c; //b qua du :
cin >> w;
cout << "Case " << no << ": ";
solve(l, w);

}
return 0;
}

51/61

K thut phn tch v thit k gii thut

Gii thut trn th

6.1 Gii thut Dijkstra tm ng i ngn nht


Cho th (c hng hoc v hng u c), tm ng i ngn nht t s n tt c cc
nh cn li.
tng chnh ca gii thut l bt u t nh s (nh du s c xt ri), ta tm nh c
khong cch ngn nht t s n n, t s l nh mi ny. Xt cc nh c cung ni trc tip
vi s v cp nht li khong cch mi nu ng i c di hn. nh du s c xt. Tip
tc qu trnh ny cho n khi tt c cc nh u c xt.
Gii thut Dijstra
#define MAX 501
#define Inf 50000
int M[MAX][MAX];
int check[MAX];
int d[MAX];
void Dijkstra (int n, int t) {
//1. Khi to cha nh no c xt, d[i] = v cng
memset(check, 0, sizeof(check));
for (int i = 0; i < n; i++)
d[i] = Inf;
int s = t;
d[s] = 0;
for (int j = 0; j < n; j++)
if (M[s][j] < Inf)
d[j] = M[s][j];
check[s] = 1;

for (int i = 1; i < n; i++) {


//2. tm phn t nh nht
int MIN = Inf;
s = -1;
for (int k = 0; k < n; k++)
if (!check[k] && d[k] < MIN) {
MIN = d[k];
s = k;
}
if (s == -1)
break;
//3. cp nht d[j] ca cc con ca s
for (int j = 0; j < n; j++) {
int newcost = d[s] + M[s][j];
if (!check[j] && M[s][j] < Inf && d[j] > newcost)
d[j] = newcost;
}
check[s] = 1;
}

1019 - Brush (V): tm ng i ngn nht t nh 1 n nh n trong th


p dng trc tip gii thut Dijsktra gii bi ny.
52/61

K thut phn tch v thit k gii thut

Bin th ca Dijstra: Xt bi 1002 - Country Roads


I am going to my home. There are many cities and many bi-directional roads between
them. The cities are numbered from 0 to n-1 and each road has a cost. There are m roads.
You are given the number of my city t where I belong. Now from each city you have to
find the minimum cost to go to my city. The cost is defined by the cost of the maximum
road you have used to go to my city.

For example, in the above picture, if we want to go from 0 to 4, then we can choose
1)
2)
3)

0 - 1 - 4 which costs 8, as 8 (1 - 4) is the maximum road we used


0 - 2 - 4 which costs 9, as 9 (0 - 2) is the maximum road we used
0 - 3 - 4 which costs 7, as 7 (3 - 4) is the maximum road we used

So, our result is 7, as we can use 0 - 3 - 4.


Input
Input starts with an integer T ( 20), denoting the number of test cases.
Each case starts with a blank line and two integers n (1 n 500) and m (0 m
16000). The next m lines, each will contain three integers u, v, w (0 u, v < n, u v, 1
w 20000) indicating that there is a road between u and v with cost w. Then there will be
a single integer t (0 t < n). There can be multiple roads between two cities.
Output
For each case, print the case number first. Then for all the cities (from 0 to n-1) you have
to print the cost. If there is no such path, print 'Impossible'.
Sample Input
2
56
015
014
213
307
346
318
1
54
015
014
213
347
1

Output for Sample Input


Case 1:
4
0
3
7
7
Case 2:
4
0
3
Impossible
Impossible

53/61

K thut phn tch v thit k gii thut

Tm ng i ngn t cc thnh ph n thnh ph t. Do cc ng ni l ng hai chiu


nn bi ton tng ng vi tm ng i ngn nht t t n cc thnh ph khc. Chi ph ca
ng i c tnh bng di cung di nht trn ng i.
Tm ng c chi ph nh nht vi chi ph ca ng i c tnh bng chi ph ca cung ln
nht trn ng i.
Vi bi ton ny ta ch cn u chnh 1 cht phn cp nht chi ph ng i. Nu d[i] l chi
ph ng i t s n i, v c[i][j] l chi ph ca cung (i, j) th ta s cp nht chi ph ca ng
i t s n j, d[j] = max(d[i], c[i][j]) nu chi ph mi ny tt hn chi ph c d[j].
Cn ch gia hai nh c th c nhiu cung. Ta ch cn gi li cung c chi ph nh nht.
No, cc bn th submit nh !
//1002 - Country Roads
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <iostream>
#include <map>
using namespace std;
#define MAX 501
#define Inf 50000
int M[MAX][MAX], check[MAX], d[MAX];
void Dijkstra(int n, int t) {
memset(check, 0, sizeof(check));
for (int i = 0; i < n; i++)
d[i] = Inf;
int s = t;
d[s] = 0;
for (int j = 0; j < n; j++)
if (M[s][j] < Inf)
d[j] = M[s][j];
check[s] = 1;
for (int i = 1; i < n; i++) {
//tm phn t nh nht
int MIN = Inf;
s = -1;
for (int k = 0; k < n; k++)
if (!check[k] && d[k] < MIN) {
MIN = d[k];
s = k;
}
if (s == -1)
break;
for (int j = 0; j < n; j++) {
int newcost = max(d[s], M[s][j]);
if (!check[j] && M[s][j] < Inf && d[j] > newcost)
d[j] = newcost;
}
54/61

K thut phn tch v thit k gii thut

check[s] = 1;
}
for (int i = 0; i < n; i++)
if (d[i] < Inf)
printf("%d\n", d[i]);
else
printf("Impossible\n");
}
int main() {
int nCase, n, m, t, u, v, c;
scanf("%d", &nCase);
for (int no = 1; no <= nCase; no++) {
scanf("%d %d", &n, &m);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
M[i][j] = Inf;
for (int i = 0; i < m; i++) {
scanf("%d %d %d", &u, &v, &c);
if (M[u][v] > c)
M[u][v] = M[v][u] = c;
}
scanf("%d", &t);
printf("Case %d:\n", no);
Dijkstra(n, t);
}
return 0;
}

Ch : gii thut Dijsktra chy c l nh vo mt gi thit sau y:


-

Trong qu trnh thc hin gii thut, chiu di ng i ngn nht t nh bt u n


mt nh bt k s gim dn. Ti mi thi im, nu ng i t nh bt u i n 1
nh v l ngn nht so vi cc nh cn li th ng i ny l ng i ngn nht.
Gi thit ny ch ng khi th khng cha cung c trng s m. Nu trng s cc
cung l dng th khng th no ta c mt nh no c d[u] > v m sao i t u
v v li nh hn d[v] c.
d[v]

c[u,v]

s
d[u]

55/61

K thut phn tch v thit k gii thut

6.2 Gii thut Kruskal tm cy khung c trng s nh nht


Cho th v hng G, cy T c gi cy khung ca th t nu:
-
-
-

T gm cc nh ca G
T lin thng
T khng cha chu trnh

Cy khung ca mt th n nh c ng n-1 cnh.


Trng s ca mt cy khung bng tng trng s cc cung trn cy.
Cy khung nh nht l cy c trng s nh nht.
C 2 gii thut tm kim cy khung nh nht ca mt th v hng: gii thut Prim (thao
tc theo inh) v gii thut Kruskal thao tc theo cnh.
tng ca gii thut nh sau:
-
-
-
-
-

Sp xp cc cnh theo th t tng dn


Kh to cy T khng c cnh no c
Ln lt xt tng cnh ( sp xp) xem c th a vo cy T khng. Ta s a mt
cnh c vo cy T nu sau khi thm n T khng cha chu trnh.
Gii thut kt thc khi: T c n-1 cnh (n l s nh) hoc tt c cc cnh xem
xt.
Nu sau khi kt thc T khng c n-1 cnh c ngha l th ban u khng lin
thng.

Mu cht ca gii thut Krusskal nm ch xt xem T c chu trnh nu thm cnh c vo


khng. C mt cnh kh n gin nhng hiu qu gii quyt vn ny nh sau:
Ta xem T nh mt rng (gm nhiu cy). Khi khi to T gm n cy, mi cy ch c 1 nt.
Khi thm mt cnh c vo, nu cnh ny c 2 nh/nt nm 2 cy khc nhau th chc chn
khng to nn chu trnh, ngc li th thm c vo T s cha chu trnh.
ci t ta s dng mt mng p lu cha ca mt nh. Bng cch ny ta s lu c cc
cy trong rng T.
Khi to, p[i] = i (hoc = -1 cng c, cho bit i l nt gc ca cy).
Khi thm cnh c = (u, v) vo cy ta s tm gc ca u v gc ca v. Nu u v v c chung gc,
c ngha l n cng chung 1 cy, ngc li n nm 2 cy khc nhau.
Gii thut tm gc ca 1 nt v kh n gin, ta ln ngc ln cha ca n (da vo mng p)
c p[v], p[p[v]], cho n khi p[i] = i th i l gc. Sau khi tm c gc ca v l i.
tit kim cho cc ln tm gc sau ta gn p[v] = i lun.
Gii thut Kruskal:
int findRoot(int v) {
int node = v;
//Trong khi node cha phi l gc, ln ln cha ca n
while (p[node] != node)
node = p[node];
//Kt thc vng lp node l nt gc
//Gn p[v] = node lun, ln sau tm gc ca v cho
//nhanh, ch cn ln ln mt bc.
p[v] = node;
return p[v];
}
56/61

K thut phn tch v thit k gii thut

int Kruskal(int n, int m) {


//1. Khi to n nt gc ca n cy trong rng T
for (int i = 1; i <= n; i++)
p[i] = i;
//2. Sp xp cc cnh theo trng s tng dn
sort(edges, edges + m, compare);
int sum = 0, cnt = 0;
//3. Duyt qua tng cnh
for (int i = 0; i < m && nb_edges < n-1; i++) {
int rx = findRoot(edges[i].x);
int ry = findRoot(edges[i].y);
//3.1 nu chung gc => b qua
if (rx == ry)
continue;
//3.2 nu khc gc, gom 2 cy thnh 1
p[ry] = rx;
sum += edges[i].c;
//3.2 tng s cnh trong T
nb_edges++;
}
//4. tr v trng s ca cy
return sum;
}
1040 - Donation: quyn gp cp Ethernet
Bn c n cn phng, nh s t 1 n n. Gia cc cn phng c th c ni vi nhau bng 1
si cp c chiu di c. Vic kt ni gia cc cn phng c m t bng 1 ma trn nh bn
di:
0 10 10 0
0 0

0 0

0 0

Phn t (i, j) cho bit chiu di ca dy cp ni gia phng i v phng j. Bn ch mun gi li


cc si cp cn thit hai phng bt k lun c kt ni (trc tip hoc thng qua mt s
phng khc). Cc si cp tha bn dng quyn gp. Hy tnh tng chiu di di nht ca
cc on cp m bn c th quyn gp. Nu ban u c 2 phng khng c kt ni vi nhau
tr v -1.
Trong v d trn, bn c th quyn gp nhiu nht l: 10 + 2 + 5 = 17. Cc phng vn cn
c kt ni: (1, 2) (2, 3) (3, 4).
gii bi ny ta c th p dng trc tip gii thut Kruskal.
-
-

Sp xp cc cnh theo th t tng dn.


Ln lt xt tng cnh, vi mi cnh nu thm c vo rng T ta tng s cung s
dng ln 1. nh du n c s dng. Gii thut dng li khi xt ht cc cnh
hoc s cnh s dng = n-1.
57/61

K thut phn tch v thit k gii thut

Nu s cnh s dng < n-1 tr v -1, ngc li ta tnh tng chiu di cc on cp


khng s dng v tr v tng ny.

Bn th code v submit th i nh!


1059 - Air Ports: xy cc sn bay v cc con ng ni gia cc thnh ph.
Cho n thnh ph, ta cn phi xy dng 1 s sn bay ti 1 s thnh ph v xy nhiu nht l
m con ng ni t thnh ph ny n thnh ph khc. Mc tiu l t bt c thnh ph no
hoc l n c sn bay hoc l c ng ta i n 1 thnh ph khc c sn bay. Xy dng
con ng ni 2 thnh ph x, y tn 1 chi ph l c. Xy 1 sn bay tn 1 chi ph l A. Hy tm
cch xy cc sn bay v con ng sao cho tng chi ph thp nht. Nu c 2 phng n c
chi ph bng nhau ta chn phng n c nhiu sn bay nht. Ch : ta ch c th xy nhiu
nht m con ng.
y l mt bin th ca bi ton cy khung nh nht. Ta nhn xt:
-
-

Nu c ng i t thnh ph x n thnh ph y (trc tip hay gian tip thng qua cc


thnh ph khc) th ta khng cn phi xy thm ng x n y. V ta cng ch cn 1
sn bay l cho x v y.
Nu x c sn bay v y l mt thnh ph th ta c 2 gii php: hoc l xy thm 1
sn bay ti y hay xy thm 1 con ng n 1 thnh ph no lin thng vi x. Ta
s chn gii php c chi ph thp nht.

Vi nhn xt ny ta c gii thut gii bi ton nay nh sau:


-
-
-
-

Khi to, rng T c n gc, s sn bay cn phi xy = n


Sp xp cc con ng theo th t tng dn theo chi ph
Ln lc xt cc con ng, nu chi ph xy dng n ln hn chi ph xy bay ta dng
gii thut. V xy con ng c hn xy sn bay. Cc con ng sau n s c chi ph
ln hn n (cc con ng sp xp).
Nu chi ph ca con ng nh hn chi ph xy sn bay, ta s thm n vo rng T nu
hai u mt ca n nm hai cy khc nhau, gim s sn bay cn phi xy i 1 (gom
2 cy khc nhau li thnh 1 cy th ch cn 1 sn bay). Ngc li ta b qua.

Khi gii thut kt thc, ta c tng chi ph ca cc con ng v s sn bay cn phi xy. In
kt qu ny ra.
No, cc bn th submit nh !
//1059 - Air Ports
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <iostream>
#include <map>
using namespace std;
#define MAX 100001
struct Edge {
int x, y, c;
};
Edge edges[MAX];
int p[10001];
58/61

K thut phn tch v thit k gii thut

bool compare(const Edge& a, const Edge& b) {


return a.c < b.c;
}
int findRoot(int v) {
int node = v;
while (p[node] != node)
node = p[node];
p[v] = node;
return p[v];
}
void Kruskal(int n, int m, int a) {
for (int i = 1; i <= n; i++)
p[i] = i;
int sum = 0, nb_tree = n;
sort(edges, edges + m, compare);
for (int i = 0; i < m && edges[i].c < a; i++) {
int px = findRoot(edges[i].x);
int py = findRoot(edges[i].y);
if (px == py)
continue;
p[py] = px;
sum += edges[i].c;
nb_tree--;
}
printf("%d %d\n", sum + a*nb_tree, nb_tree);
}
int main() {
int nCase, n, m, a, u, v, c;
scanf("%d", &nCase);
for (int no = 1; no <= nCase; no++) {
scanf("%d %d %d", &n, &m, &a);
for (int i = 0; i < m; i++) {
scanf("%d %d %d", &edges[i].x,
&edges[i].y, &edges[i].c);
}
printf("Case %d: ", no);
Kruskal(n, m, a);

}
return 0;
}

Tm cy khung c trng s ln nht:


tm cy khung c trng s ln nht, ta ch cn i th t sp xp t tng dn thnh gim
dn. Bn c th p dng gii bi 1029 - Civil and Evil Engineer.
59/61

K thut phn tch v thit k gii thut

Phn i v tm kim nh phn (Bisection and Binary search)

y l mt k thut c dng dung ho gia b nh v thi gian tm kim ca 1 phng


php tm kim: tm kim tun t v tm kim nh phn.
Xt bi ton n gin nh sau: cho tp N gm n s nguyn, v 1 s nguyn k hy tm xem k
c trong N khng ?
-
-

Nu dng tm kim tun t ta s ln lt xt tng phn t xem n c bng k khng.


Gii php ny tn trung bnh khong n/2 ln lp c kt qu.
Nu s dng tm kim nh phn, trc ht ta sp xp cc s ny theo th t tng/gim
dn, sau p dng chin lc tm kim nh phn. Nu khng k thi gian sp xp
dy s, ta tn log(n) ln lp c kt qu.

Nhn xt:
-

R rng, tm kim nh phn tt hn. Tuy nhin c hai gii php u phi tn b nh
lu tr l n nh lu n phn t. i vi mt s bi ton c n ln, c hai phng
php u khng th p dng c.

Tuy nhin, nu n s nguyn ca N c th c to ra bng cch t hp (cng 2 phn t) t 2


tp s nguyn L v R c kch thc n1, n2 (n1*n2 = n, trong nhiu trng hp ta c th chn
! = ! = ), ta s c mt gii php tm k trong n s mt cch hiu qu:
-
-

Gi nguyn tp L v sp xp tp R
tm xem k c trong n s nguyn ny khng, ta ln lt xt tng phn t L[i], nu k
>= L[i], th ta tm xem phn cn li k L[i] c trong tp R khng. Nu c th k c mt
trong n s nguyn. Nu sau khi duyt qua tt c cc phn t ca L m vn khng
tm thy th k khng c trong n s nguyn.

Bng cch ny ta ch cn tn n1 + n2 nh (nu n1= n2, ta ch tn 2 nh). Thi gian tm


kim s bng n1*log(n2).
Nh th tng chnh ca k thut ny c th tm tt thng qua 3 bc sau y:
(1) To 2 tp L, R sao cho vic t hp L v R s to ra n phn t ca tp N
(2) Sp xp tp R
(3) Ln lt xt tng phn t ca L, vi mi phn t L[i], thc hin tm kim f(k, L[i])
trong tp R vi f(k, L[i]) l mt hm no ph thuc vic t hp 2 tp hp. V d:
nu php ton t hp l +, th f(k, L[i]) = k L[i].
Bc (1) l quan trng nht !
1235 - Coin Change (IV): bi ton i tin quen thuc !
Cho n loi ng xu mnh gi tng ng l A1, A2, , An. Tm xem c cch no to ra s
tin c gi tr k sau cho mi loi mnh gi ta ch c dng ti a 2 ln. Nu c tr v Yes
nu khng tr v No. Cc rng buc (1 n 18) v (1 k 109)
V d: cho 2 loi ng xu mnh gi 1 v 2. Nu k = 5 ta c to ra c v 5 = 1*1 + 2*2 (1
ng 1 xu v 2 ng 2 xu).
Ta khng th dng quy hoch ng gii bi ny v k c gi tr qu ln.
R rng nu lit k tt c cc s tin c th c to ra t cc mnh gi trn th s phn t s
l 318 (mi ng xu ta c 3 cch chn: 0, 1, 2 v ta c nhiu nht l 18 ng xu). Con s ny
qu ln, khng th lu tr. Ta s tm 2 tp hp khc sao cho t hp hai tp ny th s c
318 phn t theo yu cu.
60/61

K thut phn tch v thit k gii thut

Di y l mt phng php phn i dng to ra 2 tp hp tho mn yu cu:


-

Tch cc ng xu thnh 2 nhm:


o nhm 1 gm A1, A2, , Am
o nhm 2 gm: Am+1, Am+2, , An (vi m = n/2).
To tp hp L cha cc s tin c th c to ra t ng xu trong nhm 1, mi ng
xu s dng nhiu nht l l 2 ln
To tp hp R cha cc s tin c th c to ra t ng xu trong nhm 2, mi ng
xu s dng nhiu nht l l 2 ln
R rng nu t hp L v R ta s c c cc s tin c to ra t n loi ng xu.

-
-
-

S phn t ca L v R nhiu nht l 39 =19683 ta th lu tr d dng.


Vn cui cng l to tp L v R nh th no. Bi ton ton ny tng ng vi vic lit k
cc (chui) s tam phn c chiu di m. Nu ta quen vi cch lit k s nh phn ta c th
p dng/m rng cch cho vic lit k. Nu khng, ta c th s dng 1 phng php cng
hiu qu khng km di y:
-
-

nu m = 0, (chui) s tam phn l rng, tng cc phn t c gi tr 0.


Nu m > 1, gi L[1], L[2], .L[cnt] l cc phn t c chiu di m-1, ta to cc phn
t c chiu di m bng cch ln lt thm 0, 1, 2 vo cui cc phn t trn.

Gii thut sinh ra cc s tin t cc ng tin t A1 n Am nh sau:


L[0] = 0;
cnt = 1;
for (int i = 1; i <= m; i++) {
N1 = cnt;
for (int j = 0; j < N1; j++)
L[cnt++] = L[j] + A[i];
//dng A[i] 1 ln
L[cnt++] = L[j] + 2*A[i]; //dng A[i] 2 ln
//cc phn t L[0] -> L[N1-1] l cc s tin
//c to ra m khng dng A[i]
}
}
Lm tng t sinh ra tp R t cc ng xu Am+1, Am+2, , An.
No, cc bn th submit nh !
Bi tng t:
1127 Funny Knapsack

61/61

You might also like