Documente Academic
Documente Profesional
Documente Cultură
2014
Suport de curs
Lot
Operaii pe bii naional
Juniori
1
Operaii pe bii
1. Reprezentarea intern a numerelor ntregi
3 5 8 7
7 6 5 4 3 2 1 0
bitdesemn:
0 ptrnrpozitiv
1 ptrnrnegativ
Exemplu:
S determinm forma de reprezentare a numrului ntreg 5.
510 =1012
Vor fi necesare 4 cifre de 0 nesemnificative, pentru completarea primelor 7 biii, iar poziia 7 (bitul 8)
va fi 0 deoarece numrul este pozitiv.
Deci reprezentarea intern este urmtoarea:
3
0 5
0 80 70 0 1 0 1
7 6 5 4 3 2 1 0
Nu n acelai mod se face reprezentarea numerelor ntregi negative. Pentru aceasta este necesar
efectuarea urmtorilor pai:
1) determinarea reprezentrii interne a numrului ce repezint valoarea absolut a numrului iniial.
Acesta are bitul de semn egal cu 0.
2) se calculeaz complementul fa de 1 a reprezentrii obinute la pasul anterior (bitul 1 devine 0, iar
bitul 0 devine 1)
3) se adun 1 (adunarea se face n baza 2) la valoarea obinut.
Exemplu:
Pentru determinarea reprezentrii numrului -5 se procedeaz n felul urmtor:
Reprezentarea valorii absolute a numrului -5 este 00000101.Complementul fa de 1 este:
11111010
Numrul obinut dup adunarea cu 1 este :
11111011
Deci reprezentarea valorii ntregi -5 pe 8 bii este:
2
3
1 5
1 81 71 1 0 1 1
7 6 5 4 3 2 1 0
Dup cum observm bitul de semn este 1 ceea ce ne indic faptul c avem de a face cu un
numr negativ.
Putem trage concluzia c numerele ntregi care se poate reprezenta pe 8 bii sunt cuprinse ntre
100000002 i 011111112 , adic -12810, 12710.
Operatorii pe bii se pot aplica datelor ce fac parte din tipurile ntregi. Operaiile se efectueaz asupra
biiilor din reprezentarea intern a numerelor.
Operatorul de negaie
not (Pascal) respectiv ~ (C/C++)
Este un operator unar care ntoarce numrul ntreg a crui reprezentare intern se obine din
reprezentarea intern a numrului iniial, prin complementarea fa de 1 a fiecrui bit(10 i 01).
Exemplu:
not 5=-6 ~ 5 == -6
Reprezentarea lui 5 este 00000101. Complementnd acest numr obin reprezentarea 11111010
care corespunde numrului ntreg - 6. S verificm:
6 se reprezint intern astfel:
62 = 00000110, complementnd obinem 11111001 i adunnd 1 (n baza 2) se obine n final
11111010 adic exact reprezentarea intern returnat a numrului returnat de operaia not 5
respectiv ~5.
Operatorul de conjuncie
and respectiv &
Este un operator binar care returneaz numrul ntreg a crui reprezentare intern se obine prin
conjuncia biilor care apar n reprezentarea intern a operanzilor. Conjuncia se face cu toate perechile
de bii situai pe aceeai poziie.
Exemplu:
5 and 3 = 1 5 & 3 == 1
S verificm:
Reprezentarea intern a lui 5 este 00000101, iar a lui 3 este 00000011.
00000101 and 00000101 &
00000011 00000011
00000001 00000001
3
Aceast reprezentare este dat de numrul ntreg 1.
Operatorul de disjuncie
or respectiv |
Este un operator binar care returneaz numrul ntreg a crui reprezentare intern se obine prin
disjuncia biilor care apar n reprezentarea intern a operanzilor. Disjuncia se face ntre biii situai pe
aceeai poziie.
Exemplu:
15 or 3=15 15 | 3==15
S verificm:
Reprezentarea intern a lui 15 este 00001111 iar a lui 3 este 00000011.
00001111 or 00001111 |
00000011 00000011
00001111 00001111
Aceast reprezentare este dat de numrul ntreg 15.
Este un operator binar care returneaz numrul ntreg a crui reprezentare intern se obine prin
operaia or exclusiv asupra biilor care apar n reprezenarea intern a operanzilor. Operaia se face ntre
biii situai pe aceeai poziie.
Exemplu:
15 xor 3=12 15 ^ 3==12
S verificm:
Reprezentarea intern a lui 15 este 00001111 iar a lui 3 este 00000011.
00001111 xor 00001111 ^
00000011 00000011
00001100 00001100
Este un operator binar care returneaz numrul ntreg a crui reprezentare este obinut din
reprezentarea intern a primului operand prin deplasare la stnga cu un numr de bii egal cu al doilea
operand.
Exemplu:
4 shl 2=16 4 << 2==16
S verificm:
Reprezentarea intern a lui 4 este 00000100. Prin deplasare la stnga cu doi bii se obine
00010000, care este reprezentarea intern a lui 16.
Acest operator poate fi folosit pentru calculul numerelor ntregi de forma 2n prin efectuarea operaiilor
de forma 1 shl n. (1<<n)
4
Operatorul shift right
shr respectiv >>
Este un operator binar care returneaz numrul ntreg a crui reprezentare este obinut din
reprezentarea intern a primului operand prin deplasare la dreapta cu un numr de bii egal cu al doilea
operand.
Prin deplasarea la dreapta, primii biii din reprezentarea intern a numrului (poziiile 1,2, .a.m.d.) se
pierd iar ultimii se completeaz cu zero.
Exemplu:
14 shr 2=3 14 >> 2==3
S verificm:
Reprezentara intern a numrului 14 este 000001110. Prin deplasare la dreapta cu doi bii a
reprezentrii lui 14 se obine 00000011, care este reprezentarea intern a lui 3.
Operaia n shr 1 (n>>1) este echivalent cu mprirea ntreag la 2.
X 00110010 OR X 00110010 |
M 00000100 M 00000100
Rez 00110110 Rez 00110110
S lum ca exemplu X= 109, pentru a vedea cum se seteaz un bit la valoarea 0. Reprezentarea intern
a lui este 01101101. Se cere s se seteze bitul 5 la valoarea 0. De data aceasta masca va conine toi
biii de 1, excepie bitul 5. Aspura lui X i M vom aplica I logic.
Masca mai poate fi obinut i aplicnd sau exclusiv n locul scderii, 255 xor (1 shl B).
Rescriem rezultatul sub forma:
X and (255 xor(1 shl B)) X & (255 ^(1 << B))
5
Testarea valorii unui bit
Plecm de la valoarea X=47. Reprezentarea intern a lui este 00101111. Presupunem c dorim s
cunoatem valoarea bitului 3 i bitului 6. Vom folosi mtile M1=00001000 i M2=01000000.
Vom aplica de fiecare dat I logic ntre X i cele dou mti:
Pornim de la valoarea ntreag X=50. Reprezentarea acestuia pe 8 bii este 00110010. Presupunem
c dorim s cunoatem restul la mprirea ntreag a lui X la 8, adic X mod 8 respectiv x%8.
Valoarea ultimilor 3 bii din reprezentarea intern a lui lui, reprezint tocmai acest rest. Pentru aceasta
vom folosi o masc n care ultimii trei biii sunt 1 restul 0. Aceasta masc are valoarea 7, adic
00000111. Vom aplica operaia I logic.
Pe caz general, dac dorim s cunoatem valoarea ultimilor B bii(care este egal cu restul mpririi lui
X la 2B) vom exprima astfel:
6
Aplicaii
Problema 1.
Realizai un subprogram care determin numrul de cifre de 1 din reprezentarea binar a unui
numr natural nenul n mai mic ca 2000000000.
Soluia 1:
Numrul l vom reine ntr-o variabil longint respectiv int i vom parcurge secvenial biii lui.
function nr( n:longint):byte; int nr (int n){
var nm,i:byte; int nm=0;
begin for ( int i=0; i<32; i++)
nm:=0; if (n & (1 << i)) nm++;
for i:=0 to 31 do return nm;
if n and (1 shl i) <>0 then }
inc(nm);
nr:=nm;
end;
Soluia 2:
O alt soluie, mai rapid este folosirea operaiei I logic ntre valorile lui n i a lui n-1.
Aceast operaie anuleaz cel mai nesemnificativ bit de 1 a lui n. S luam ca exemplu valoarea lui n:
n =(110011101000100)2 n =(110011101000100)2
n-1 =(110011101000011)2 n-1 =(110011101000011)2
n and (n-1) =(110011101000000)2 n & (n-1) =(110011101000000)2
Problema 2.
Realizai un subprogram care verific dac un numr natural nenul n este o putere a lui 2.
Soluie:
Dac n este o putere a lui 2, va avea o singur cifr de 1 n reprezentarea binar. Dac
ne bazm pe observaia de la problema anterioar, obinem:
7
Problema 3.
Realizai un subprogram care identific cea mai mare putere a lui 2 care l divide pe n, numr
natural nenul.
Soluia 1:
Problema se reduce la determinarea celui mai nesemnificativ bit de 1 din reprezentarea binar a
lui n. Prima soluie caut poziia, pornind cu bitul 0.
Soluia 2
Se bazeaz pe observaia c n and (n-1) are ca rezultat numrul din care lipsete cel mai
nesemnificativ bit de 0. Atunci aplicnd XOR intre valoarea inial a lui n i ce a lui n and(n-1)
vom obine valoarea cerut.
Exemplu:
n =(101000100)2 n =(101000100)2
n and (n-1) =(101000000)2 n & (n-1) =(101000000)2
n xor(n and (n-1))=(000000100)2 n ^( n & (n-1))=(000000100)2
Problema 4.
Realizai un subprogram care identific numrul de ordine al celui mai semnificativ bit de 1 al
lui n numr natural nenul.
Soluie
Problema 5
Gigel trebuie s cumpere n medicamente, numerotate de la 1 la n. Doctorul i-a dat m reete de dou
tipuri, codificate cu numerele 1, 2 astfel:
1 - reet necompensat, adic preul medicamentelor de pe reet se achit integral de ctre
cumprtor;
2 - reet compensat 50%, adic preul medicamentelor nscrise pe reet se njumtete.
Se tie c pe reete nu exist un alt medicament dect cele numeroatete de la 1 la n i o reet nu
conine dou medicamente identice.
Dac o reet este folosit atunci se vor cumpra toate medicamentele nscrise pe ea.
Cerin
Scriei un program care s determine suma minim de bani necesar pentru a cumpra exact cte unul
din fiecare dintre cele n medicamente, folosindu-se de reetele avute la dispoziie.
Date de intrare
Fiierul de intrare reteta.in are urmtorul format :
pe prima linie sunt scrise numerele naturale n i m;
pe urmtoarele m linii sunt descrise cele m reete, cte o reet pe o linie. Linia care descrie o reet
conine tipul reetei (1 necompensat sau 2 compensat), urmat de un numr natural q
reprezentnd numrul de medicamente de pe reet, apoi de q numere distincte din mulimea {1, 2,
..., n} reprezentnd medicamentele nscrise pe acea reet;
pe ultima linie a fiierului de intrare sunt scrise n numere naturale separate prin cte un spaiu,
reprezentnd n ordinea de la 1 la n, preul medicamentelor.
Toate numerele de pe aceeai linie sunt separate prin cte un spaiu.
Date de ieire
Fiierul de ieire reteta.out va conine o singur linie pe care va fi scris un numr real cu o
singur zecimal, reprezentnd suma minim determinat.
Restricii
1 N 20
1 M 15
1 preul oricrui medicament 200; Pentru datele de test exist ntotdeauna soluie.
Exemplu
reteta.in reteta.out Explicaie
4 5 45.0 Soluia s-a obinut prin folosirea primei i celei de a patra reete.
2 1 3 O alt soluie, dar de cost mai mare, s-ar fi obinut dac se folosea reeta
2 2 2 3
1 1 1 a patra i cea de a cincea.
1 3 4 1 2
1 1 3
8 20 2 16
Timp maxim de execuie/test: 1 secund
9
Soluie
Problema admite o soluie de complexitate exponenial O(2m). Se genereaz fiecare
submulime a mulimii reetelor. Se identific acele submulimi pentru care medicamentele nscrise pe
reete includ toate cele n medicamente, fr s repete vreunul.
Se va pstra ca soluie submulimea de reete care are cost total minim. n continuare v este
prezentat o rezolvare folosind lucru pe bii.
3
5 8 7 1 1
31 ..6 5 4 3 2 1 0
n acelai mod, pentru generarea submulimilor de reete ce vor fi folosite, ne vom folosi de vectorii
caracteristici asociai acestora. Pentru aceasta vom utiliza reprezentarea binar a tuturor numerelor de
la 0 la 2m-1.
Dac variabila s are valoarea 11 atunci ea cuprinde prima, a doua i a patra reet. Medicamentele pe
care acestea le conin sunt codificate n L[0], L[1] i L[3].
3
5 8 7 1 1 1
31 ..6 5 4 3 2 1 0
Variabila u va reprezenta o masc logic care indic medicamentele prinse pe reetele ce aparin
submulimii curente.
const INF=2000000000; #include <stdio.h>
var L,T,C:array[0..20]of longint; #include <string.h>
P:array[0..20]of real;
n,m,i,j,k,nr_med,x,s,u:longint; int L[20],T[20],C[20],n,m,i,j;
ok:boolean; int k,nr_med,x,s,u,corect;
sum,min:real; double P[20],sum,min;
f:text;
begin int main (){
min:=INF; min=2000000000;
for s:=0 to 1 shl m -1 do begin for (s=0 ; s<=(1<<m)-1 ; s++)
sum:=0; u := 0; ok:=true; i:=0; {
while (i<m) and ok do begin sum=0; u = 0; corect=1;
if (s shr i) and 1 = 1 then for (i=0 ; i<m && corect ; i++ )
if (u and L[i])<>0 then if ((s>>i)&1)
ok:=false if (u&L[i]) corect=0;
else begin else
sum:=sum+P[i]; {
u:=u or L[i]; sum += P[i];
end; u |= L[i];
inc(i); }
end;
if ok and (sum<min) and if (corect && sum<min && u==(1<<n)-1)
( u=( 1 shl n)-1) then min:=sum; min=sum;
end; }
freopen ( "reteta.out","w",stdout);
assign(f,'reteta.out'); rewrite(f); if (min!=2000000000)
if (INF-min>0.1)then printf ( "%.1lf\n" , min );
writeln (f, min:0:1) else printf ( "imposibil\n" );
else fclose ( stdout );
writeln(f,'imposibil'); return 0;
close ( f ); }
end.
11
while x and 1=0 do begin x=i; nr=1;
nr:=nr+1; while (!(x & 1)) {
x:=x shr 1; nr++;
end; x >>= 1;
a[nr]:=a[nr] xor 1; }
end; a[nr] ^= 1;
close(f); close(g); } fclose(stdin); fclose(stdout);
end. return 0;}
Problema 7
Se dau v1 , v2 ... vk numere prime k<=20. S se determine cte numere mai mici ca un N dat
(N<=2000000000) sunt divizibile cu cel putin unul din cele K numere prime.
Exemplu
Pentru n=20 , k=4 si irul 2, 3, 5, 7 se va afia 15.
Soluie:
Se foloseste principiul includerii si al excluderii. Astfel numrul de numere divizibile cu cel puin un
numr dintre cel K este egal cu:
Nr (V1,V 2,..Vk) Vi Vi *Vj ...(1) k V1*V 2 * ..Vk
1 i n 1 i j ni
12
2. Arbori indexati binar
Arborii indexai binar reprezint o structur de date care permite efectuarea urmtoarelor operaii n
complexitata O(log N) pentru un vector de N elemente:
Operaiile descrise mai sus pot fi efectuate n complexitatea menionat folosind un arbore de intervale
(descris n capitolul anterior), dar folosirea unui arbore indexat binar ofer anumite avantaje:
Din pcate, aceast structur de date nu ofer aceeai flexibilitate precum un arbore de intervale, existnd seturi
de operaii care pot fi efectuate n complexitate logaritmic folosind doar arbori de intervale.
Eficiena acestei structuri de date nu are legtur cu echilibrarea arborelui precum alte structuri de date
convenionale, ci din modul de indexare a elementelor, innd cont de reprezentarea binar (de unde i numele
de arbore indexat binar).
Ideea de baz este c, precum un numr n poate fi exprimat ca sum de puteri ale lui 2, aa i un interval
[1n] poate fi exprimat ca reuniunea unor subintervale de lungimi egale cu puteri ale lui 2.
Astfel, dac se asociaz fiecrui element x din arbore un interval [x-2k+1x], unde k reprezint
numrul zerourilor terminale din reprezentarea binar a lui x, fiecare interval de forma [1x] poate fi exprimat
ca reuniunea a cel mult log2 N intervale, folosind procedeul (descris mai sus) de eliminare succesiv a celui mai
nesemnificativ bit de 1. Avnd stabilit aceast structur, operaia SUM(x) se efectueaz nsumnd intervalele
din descompunerea lui [1x].
9 ( 9 = 1001(2) ) - [99] 1
S luam ca exemplu un vector V cu 15 elemente, care sufer modificri succesive. Acestuia i asociem
un arbore indexat binar, reprezentat sub forma unui vector AIB n care elementele rein informaii referitoare la
intervale de elemente din V, dup cum urmeaz:
[1..1] [1..2] [3..3] [1..4] [5..5] [5..6] [7..7] [1..8] [9..9] [9..10] [11..11] [9..12] [13..13] [13..14] [15..15]
AIB[1] AIB[2] AIB[3] AIB[4] AIB[5] AIB[6] AIB[7] AIB[8] AIB[9] AIB[10] AIB[11] AIB[12] AIB[13] AIB[14] AIB[15]
1 ... ...
2 function UB(x:integer):integer; #define UB(x) (x&(-x))
3 begin UB:=(x and (-x)) end;
4 ...
5 procedure ADD(x,val:integer); int AIB[NMAX],V[NMAX];
6 var i,j:integer;
7 begin
8 i:=x; void ADD(int x,int val)
9 while i<=n do begin {
10 inc(AIB[i],val); int i;
11 inc(i,UB(i)); for(i=x;i<=N;i+=UB(i)) AIB[i]+=val;
12 end; }
13 end;
14
15 function SUM(x,y:integer):integer; int SUM(int x)
16 var i,j,S:integer; {
17 begin int i,S=0;
18 i:=x;
19 while i>0 do begin for(i=x;i>0;i-=UB(i)) S+=AIB[i];
20 inc(S,AIB[i]);
21 dec(i,UB(i)); return S;
22 end; }
23 SUM:=S;
24 end;
Dei aceast structur de date nu este la fel de flexibil ca un arbore de intervale, ea poate fi extins s
suporte i alte operaii:
SUMA(x, y) suma elementelor cu poziii ntre x i y: se poate rescrie ca suma elementelor din intervalul
[1..x] minus suma elementelor din intervalul [1..y-1];
MODIFIC(x, y) actualizeaz valoarea elementului x la y, dac aceasta era mai mic dect y;
MAXIM(x) determin maximul din primele x elemente.
Aceste operaii pot fi implementate nlocuind operaia de adunare ("+") cu cea de maxim.
Cerin
S se determine cte inversiuni sunt n irul dat.
14
Date de intrare
Fiierul de intrare inv.in conine pe prima linie numrul natural N. Pe urmtoarea linie se
gsesc N numere ntregi, reprezentnd n ordine elementele irului S.
Date de ieire
n fiierul de ieire inv.out se va afia un singur numr, reprezentnd restul mpririi numrului de
inversiuni din ir la valoarea 9917.
Restricii
2 N 100 000
Exemplu
inv.in inv.out
5 4
3 4 1 2 5
Soluie:
Problema se rezolv plecnd de la numrul maxim de inversiuni dintr-un vector. irul S preluat din inv.in va
fi sortat cresctor, pentru fiecare element reindu-se i poziia iniial n S(normalizare). Din numrul maxim se
inversiuni se vor scade numrul de inversiuni ce nu s-au format, adic numrul de elemente mai mici dect cel
curent, situate naintea lui, n irul S.
ntr-un arbore indexat binar, elementul AIB[x] va reine numrul de elemente introduse pn n acel moment i
care sunt situate n irul S pe poziii ntre [x-2k+1,..,x]. Evident ele au valori mai mici dect elementul curent i
deci nu formeaz cu el inversiuni.
1 #include <cstdio>
2 #include <algorithm>
3 #include <vector>
4
5 #define ub(x) (x&(-x))
6
7 #define NMAX 100001
8 #define MOD 9917
9
10 using namespace std;
11
12 vector < pair< int,int > > V;
13 int A[NMAX];
14 int N,i,x,k;
15 long long sol;
16
17 void add(int x)
18 {
19 int i=0;
20
21 for (i=x;i<=N;i+=ub(i)) A[i]++;
22 }
23
24 int Sum(int x)
25 {
26 int i=0,S=0;
27
28 for (i=x;i>0;i-=ub(i)) S+=A[i];
29 return S;
30 }
31
32 int main()
33 {
34 freopen("inv.in","r",stdin);
35 freopen("inv.out","w",stdout);
36
37 scanf("%d",&N);
38
39 for (i=0;i<N;i++)
15
{
scanf("%d",&x);
V.push_back(make_pair(x,i+1));
}
sort(V.begin(),V.end());
sol=1LL*N*(N-1)/2;
for (i=0;i<N;i++)
{
x=V[i].second;
sol-=1LL*Sum(x);
add(x);
}
printf("%d\n",sol%MOD);
return 0;
}
La un concurs de schi, are loc o prob contra-cronometru, concurenii trebuind s termine traseul n cel
mai scurt timp cu putin. Acestia vor evolua consecutiv i, dup finish, li se va comunica locul ocupat n
clasamentul intermediar. Mai exact, dupa evolutia celui de-al p-lea concurent, acesta va ti locul su n
clasamentul format de primii p concurenti. Cunoscnd poziiile intermediare, se cere s se determine
clasamentul final al competiiei.
Date de intrare
Pe prima linie a fiierului de intrare schi.in se afl N, reprezentnd numrul de concureni aliniai la
startul concursului. Pe urmtoarele N linii se afl cte o valoare ntreag, indicnd locul ocupat de fiecare
concurent n clasamentul intermediar, actualizat dup evoluia sa.
Date de ieire
Fisierul de iesire schi.out va avea N linii. Pe linia i se va afia numrul de ordine al concurentului
care ocupa locul i n clasamentul final.
Restricii
1 N 30 000
Exemplu
inv.in inv.out
8 7
1 2
1 8
3 6
4 1
4 3
2 5
1 4
3
Soluie:
Pentru a rezolva problema vom reine, ntr-un arbore indexat binar numrul de poziii libere n clasamentul final.
Astfel, elementul AIB[x] va reine cte poziii libere exist ntre [x-2k+1,..,x]. Se va parcurge invers irul din
fiierul de intrare, i pentru fiecare valoare X[i], se va determina cea mai mica poziie x pentru care suma
elementelor din AIB pe intervalul [1..x] este egal cu X[i].
Poziia x este poziia din clasamentul final a concurentului cu mumrul de ordine i.
1 #include <cstdio>
2 #include <climits>
3 #define ub(x) (x&(-x))
4 #define NMAX 30001
5
6 using namespace std;
7
16
8 int A[NMAX],X[NMAX],sol[NMAX];
9 int N,i,x;
10
11 void Decrease(int x)
12 {
13 int i;
14 for(i=x;i<=N;i+=ub(i)) A[i]--;
15 }
16
17 int Sum(int poz)
18 {
19 int i=0,T=0;
20 for(i=poz; i>0; i-=ub(i)) T+=A[i];
21 return T;
22 }
23
24 int binary_search(int x)
25 {
26 int S=1,D=N,M=0,T=0,Minim=INT_MAX;
27 while(S<=D)
28 {
29 M=(S+D)/2;
30 T=Sum(M);
31 if (T==x && M<Minim) Minim=M;
32 else if (T>=x) D=M-1;
33 else S=M+1;
34 }
35 return Minim;
36 }
37
38 int main()
39 {
40 freopen("schi.in","r",stdin);
41 freopen("schi.out","w",stdout);
42
43 scanf("%d",&N);
44 for (i=1; i<=N; ++i) scanf("%d",&X[i]);
45 for (i=1; i<=N; ++i) A[i]=ub(i);
44
45 for (i=N; i>=1; --i)
46 {
47 x=binary_search(X[i]);
48 sol[x]=i;
49 Decrease(x);
50 }
51
52 for (i=1;i<=N;++i) printf("%d\n",sol[i]);
53
54 return 0;
55 }
Se consider N copii aezai n cerc i numerotai de la 1 la N n sens trigonometric. Copiii joac urmtorul joc:
jocul ncepe de la primul copil (cel al crui numr de ordine este 1); la fiecare al i-lea pas al jocului se
numar i copii in sens trigonometric i este eliminat copilul la care se ajunge; la pasul urmtor numrtoarea
ncepe de la copilul care urmeaz dup cel eliminat.
Aadar, dac numrul copiilor este suficient de mare, la primul pas este eliminat al doilea copil, la al doilea pas
al patrulea, la al treilea pas al aptelea, apoi la al patrulea pas al unsprezecelea i aa mai departe.
Cerin
Va trebui s determinai ordinea n care vor fi eliminai copiii.
Date de intrare
Fiierul de intrare order.in conine pe prima linie un numar intreg N, care reprezint numrul de copii.
Date de ieire
17
Fiierul de ieire order.out trebuie s conin o singura linie pe care se vor afla N numere distincte cuprinse
ntre 1 i N care reprezint numerele de ordine ale copiilor n ordinea n care au fost eliminai.
Restricii
2 N 30 000
Exemplu
order.in order.out
6 2 4 1 3 5 6
Soluie:
n mod asemntor, n AIB vom reine la fiecare pas, copiii rmai n cerc. Pentru fiecare extragere se va
identifica, printr-o cutare binar, cel mai mic indice x din AIB, pentru care suma [1..x] este egal cu cel a
copilului ce urmeaz la extragere.
1 #include <cstdio>
2 #include <climits>
3 #define ub(x) (x&(-x))
4 #define NMAX 30001
5
6 using namespace std;
7
8 int A[NMAX],sol[NMAX];
9 int x,N,i,ind,P=2;
10
11 void add(int x,int val)
12 {
13 int i=0;
14 for(i=x;i<=N;i+=ub(i)) A[i]+=val;
15 }
16
17 int Sum(int x)
18 {
19 int i=0,S=0;
20 for(i=x;i>0;i-=ub(i)) S+=A[i];
21 return S;
22 }
23
24 int binary_search(int x)
25 {
26 int D=N,S=1,M=0,Sm=0,Minim=INT_MAX;
27
28 while(S<=D){
29 M=(S+D)/2;
30 Sm=Sum(M);
31 if( Sm==x && M<Minim) Minim=M;
32 else if (Sm>=x) D=M-1;
33 else S=M+1;
34 }
35 return Minim;
36 }
37
38 int mod(int x,int MOD)
39 {
40 if (!(x%MOD)) return MOD;
41
42 return x%MOD;
43 }
44
45 int main()
44 {
45 freopen("order.in","r",stdin);
46 freopen("order.out","w",stdout);
47 scanf("%d",&N);
48 for(i=1;i<=N;++i) add(i,1);
49 ind=N;
50
18
51 for(i=1;i<=N;++i)
52 {
53 --ind;
54
55 x=binary_search(P);
56 add(x,-1);
57
58 sol[i]=x;
59 P+=i;
60
61 if (ind!=0) P=mod(P,ind);
62 }
63
64 for(i=1;i<=N;++i) printf("%d ",sol[i]);
65 return 0;
66 }
Probleme suplimentare:
Pe campion.edu.ro
Concurs1:
Pe infoarena.ro:
Datorii
AIB
Ben
Evantai
19