Diferente pentru probleme-cu-secvente intre reviziile #26 si #25

Nu exista diferente intre titluri.

Diferente intre continut:

h2(#prob1). Problema 1 (Subsecvenţa de sumă maximă)
bq. Se dă un şir de $N$ numere întregi $(a{~1~}, a{~2~}, ..., a{~N~})$. Să se determine o subsecvenţă $(a{~i~}, a{~i+1~}, ..., a{~j~})$ care să aibă suma maximă.
Se dă un şir de $N$ numere întregi $(a{~1~}, a{~2~}, ..., a{~N~})$. Să se determine o subsecvenţă $(a{~i~}, a{~i+1~}, ..., a{~j~})$ care să aibă suma maximă.
h3. Exemplu:
Prima rezolvare care ne vine în minte are complexitatea $O(N^3^)$ şi constă în determinarea sumei fiecărei subsecvenţe posibile şi reţinerea maximului acestor sume. Este evident că anumite sume parţiale sunt calculate de mai multe ori.
Putem reduce complexitatea la $O(N^2^)$ ţinând cont de faptul că suma subsecvenţei $a[i..j]$ este egală cu suma subsecvenţei $a[i..j-1]$, la care se adună $a[j]$. Păstrăm într-un şir $sum[i]$ suma elementelor din subsecvenţa $a[1..i]$. Pentru a determina suma elementelor din subsecvenţa $a[i..j]$ facem diferenţa: $sum[i] - sum[j-1]$.
Putem reduce complexitatea la $O(N^2^)$ ţinând cont de faptul că suma subsecvenţei $a[i..j]$ este egală cu suma subsecvenţei $a[i..j-1]$, la care se adună $a[j]$. Păstrăm într-un şir $sum[i]$ - suma elementelor din subsecvenţa $a[1..i]$. Pentru a determina suma elementelor din subsecvenţa $a[i..j]$ facem diferenţa $sum[i] - sum[j-1]$.
Ideea poate fi rafinată calculând pentru fiecare indice $i$ numărul $best[i]$, reprezentând subsecvenţa de sumă maximă cu capătul drept în $i$. Este uşor de observat că $best[i] = max(sum[i] - sum[j-1])$, unde $j$ ia valori de la $1$ la $i$. Relaţia anterioară se mai poate scrie: $best[i] = sum[i] - min(sum[j-1])$. Obţinem astfel un algoritm liniar care ne determină subsecvenţa de sumă maximă cerută.
Ideea poate fi rafinată calculând pentru fiecare indice $i$ numărul $best[i]$, reprezentând subsecvenţa de sumă maximă cu capătul drept în $i$. Este uşor de observat că $best[i] = max(sum[i] - sum[j-1])$, unde $j$ ia valori de la $1$ la $i$. Relaţia anterioară se mai poate scrie $best[i] = sum[i] - min(sum[j-1])$. Obţinem astfel un algoritm liniar care ne determină subsecvenţa de sumă maximă cerută.
== code(cpp) |
sum[0] = 0;
}
==
O altă metodă de calcul poate fi dedusă folosind paradigma _Divide Et Impera_. La fiecare pas împărţim şirul în jumătate şi aflăm subsecvenţele de sumă maximă din cele două jumătăţi. După aceea trebuie să găsim subsecvenţa de sumă maximă ce are un capăt în fiecare din cele două jumătăţi ale sirului. Pentru aceasta alipim sufixul de sumă maximă a primei jumătăţi cu prefixul de sumă maximă a celei de a doua.
O altă metodă de calcul poate fi dedusă folosind paradigma _Divide Et Impera_. La fiecare pas împărţim şirul în jumătate şi aflăm subsecvenţele de sumă maximă din cele două jumătăţi. După aceea trebuie să găsim subsecvenţa de sumă maximă ce are un capăt în fiecare din cele două jumătăţi ale sirului. Pentru aceasta alipim sufixul de sumă maximă a primei jumătăţi cu prefixul de sumă maximă a celei de-a doua.
== code(cpp) |
int getMaxSubsequence(int l, int r) {
O idee bazată pe paradigma programării dinamice ar fi să folosim un şir $best[i]$, reprezentând suma maximă a unei subsecvenţe ce se termină în $a[i]$. Problema se rezolvă cu următoarea formulă de recurenţă: $best[i] = max(a[i], best[i-1] + a[i])$. Formula poate fi demonstrată prin inducţie matematică.
O ultimă idee ar fi să partiţionăm şirul în subsecvenţe încât fiecare să aibă ambele capete cât mai mici posibile şi suma elementelor subsecvenţei să fie negativă. Pentru exemplul dat avem următoarea partiţionare: $[-1], [2, 3, -4, -2], [2, 1, -3, -2], [-3], [-4], [9, -2, 1, 7, 8, -19, -7], [2, 4, 3]$. O subsecvenţă de sumă maximă va avea primul capăt la începutul unei astfel de subsecvenţe, acest lucru explicându-se prin faptul că în caz contrar secvenţa poate fi mărită în stânga (orice secvenţă din cele alese pentru partiţionare are toate prefixele de sumă pozitivă, în afară de prefixul ce reprezintă întreaga subsecvenţă). De asemenea, orice subsecvenţă de sumă maximă nu va conţine elemente din altă parte a partiţiei, pentru că dacă subsecvenţa se întinde pe mai multe părţi, atunci putem elimina prefixul subsecvenţei care reprezintă o parte a partiţiei, acea parte având suma negativă.
O ultimă idee ar fi să partiţionăm şirul în subsecvenţe încât fiecare să aibă ambele capete cât mai mici posibile şi suma elementelor subsecvenţei să fie negativă. Pentru exemplul dat avem următoarea partiţionare $[-1], [2, 3, -4, -2], [2, 1, -3, -2], [-3], [-4], [9, -2, 1, 7, 8, -19, -7], [2, 4, 3]$. O subsecvenţă de sumă maximă va avea primul capăt la începutul unei astfel de subsecvenţe, acest lucru explicându-se prin faptul că în caz contrar secvenţa poate fi mărită în stânga (orice secvenţă din cele alese pentru partiţionare are toate prefixele de sumă pozitivă, în afară de prefixul ce reprezintă întreaga subsecvenţă). De asemenea, orice subsecvenţă de sumă maximă nu va conţine elemente din altă parte a partiţiei, pentru că dacă subsecvenţa se întinde pe mai multe părţi, atunci putem elimina prefixul subsecvenţei care reprezintă o parte a partiţiei, acea parte având suma negativă.
== code(cpp) |
sum = -INFINIT;
bestSum = -INFINIT;
for (i = 1; i <= N; i++) {
    sum += a[i];
    if (sum < 0)
    if (sum < 0) {
        sum = 0;
    else if (sum >= bestSum)
        bestSum = sum;
        continue;
    } else
    if (sum >= bestSum) bestSum = sum;
}
==
h2(#prob2). Problema 2 ('Maximum Sum':http://icpcres.ecs.baylor.edu/onlinejudge/index.php?option=com_onlinejudge&Itemid=8&category=3&page=show_problem&problem=44, UVa)
bq. Se dă o matrice de dimensiuni $N x N$ cu elemente întregi. Se cere determinarea unei submatrici a cărei elemente au suma maximă.
Se dă o matrice de dimensiuni $N x N$ cu elemente întregi. Se cere determinarea unei submatrici a cărei elemente au suma maximă.
h3. Exemplu:
h3. Rezolvare:
Putem folosi trucul construirii sumelor parţiale din rezolvarea anterioară, pentru cazul $2D$. Păstrăm în $sum[i][j]$ suma tuturor elementelor $a[i{~1~}][j{~1~}]$ cu proprietatea că $1 <= i{~1~} <= i$, şi $1 <= j{~1~} <= j$. Putem calcula sumele prin metoda programării dinamice în complexitate $O(N^2^)$ folosind formula: $sum[i][j] = a[i][j] + sum[i][j-1] + sum[i-1][j] - sum[i-1][j-1]$. Acum, pentru a calcula suma elementelor din matricea cu colţurile $(i{~1~}, j{~1~})$ şi $(i{~2~}, j{~2~})$, unde $i{~1~} <= i{~2~}$ şi $j{~1~} <= j{~2~}$, este suficient să facem calculul $sum[i{~2~}][j{~2~}] - sum[i{~1~}-1][j{~2~}] - sum[i{~2~}][j{~1~}-1] + sum[i{~1~}-1][j{~1~}-1]$. Astfel putem evalua suma din fiecare submatrice în timp constant, deci rezolvarea are ordinul de complexitate $O(N^4^)$.
Putem folosi trucul construirii sumelor parţiale din rezolvarea anterioară, pentru cazul $2D$. Păstrăm în $sum[i][j]$ suma tuturor elementelor $a[i{~1~}][j{~1~}]$ cu proprietatea că $1 <= i{~1~} <= i$, şi $1 <= j{~1~} <= j$. Putem calcula sumele prin metoda programării dinamice (complexitate $O(N^2^)$) folosind formula $sum[i][j] = a[i][j] + sum[i][j-1] + sum[i-1][j] - sum[i-1][j-1]$. Acum pentru a calcula suma elementelor din matricea cu colţurile $(i{~1~}, j{~1~})$ şi $(i{~2~}, j{~2~})$, unde $i{~1~} <= i{~2~}$ şi $j{~1~} <= j{~2~}$, este suficient să facem calculul $sum[i{~2~}][j{~2~}] - sum[i{~1~}-1][j{~2~}] - sum[i{~2~}][j{~1~}-1] + sum[i{~1~}-1][j{~1~}-1]$. Astfel putem evalua suma din fiecare submatrice în timp constant, deci rezolvarea are ordinul de complexitate $O(N^4^)$.
O altă idee ar fi ca pentru fiecare pereche $(i{~1~}, i{~2~})$ fixată să determinăm perechea optimă $(j{~1~}, j{~2~})$. Dacă avem liniile $i{~1~}$ şi $i{~2~}$ fixate atunci problema se transformă din una bidimensională în una unidimensională. Astfel pentru fiecare coloană $j$ vom considera $b[j]$ ca sumă a elementelor $a[i][j]$ cu proprietatea că $i{~1~} <= i <= i{~2~}$. În exemplul nostru, dacă $i{~1~} = 2$ şi $i{~2~} = 3$, atunci avem: $b{~1~} = 9 + (-4)$, $b{~2~} = 2 + 1$, $b{~3~} = (-6) + (-4)$ şi $b{~4~} = 2 + 1$. Pentru a rezolva problema unidimensională folosim unul din algoritmii liniari prezentaţi mai sus, astfel obţinându-se un algoritm de complexitate totală $O(N^3^)$. Acest truc de a fixa două linii pentru a transforma problema în una unidimensională este util în multe probleme pe matrice sau cu puncte în plan.
O altă idee ar fi ca pentru fiecare pereche $(i{~1~}, i{~2~})$ fixată să determinăm perechea optimă $(j{~1~}, j{~2~})$. Dacă avem liniile $i{~1~}$ şi $i{~2~}$ fixate atunci problema se transformă din una bidimensională în una unidimensională. Astfel pentru fiecare coloană $j$ vom considera $b[j]$ ca sumă a elementelor $a[i][j]$ cu proprietatea că $i{~1~} <= i <= i{~2~}$. În exemplul nostru, dacă $i{~1~} = 2$ şi $i{~2~} = 3$, atunci avem $b{~1~} = 9 + (-4)$, $b{~2~} = 2 + 1$, $b{~3~} = (-6) + (-4)$ şi $b{~4~} = 2 + 1$. Pentru a rezolva problema unidimensională folosim unul din algoritmii liniari prezentaţi mai sus, astfel obţinându-se un algoritm de complexitate totală $O(N^3^)$. Acest truc de a fixa două linii pentru a transforma problema în una unidimensională este util în multe probleme pe matrice sau cu puncte în plan.
Cel mai bun algoritm cunoscut pentru această problemă are complexitatea <tex>O(N^{3\sqrt{\frac{\log \log N}{\log N}}})</tex> şi este mai mult un algoritm teoretic decât unul practic, uşor implementabil. Pentru detalii puteti consulta lucrarea [3].
Cel mai bun algoritm cunoscut pentru această problemă are complexitatea <tex>O(N^{3\sqrt{\frac{\log \log N}{\log N}}})</tex> [3] şi este mai mult un algoritm teoretic decât unul practic, uşor implementabil.
h2(#prob3). Problema 3 ('SequenceQuery':problema/sequencequery, Bursele Agora 2005/2006 Runda 1)
bq. Se consideră un şir $A = (a{~1~}, a{~2~}, ..., a{~N~})$, format din numere întregi $(-100.000 <= a{~i~} <= 100.000)$, şi $M$ perechi de numere $(x, y)$ $(1 <= N, M <= 100.000)$. Pentru fiecare pereche ordonată de indici $(x, y)$ trebuie determinată subsecvenţa de sumă maximă a subşirului $a{~x~}, a{~x+1~}, ..., a{~y~}$. Subsecvenţele alese trebuie să conţină cel puţin un element.
Se consideră un şir $A = (a{~1~}, a{~2~}, ..., a{~N~})$, format din numere întregi $(-100.000 <= a{~i~} <= 100.000)$, şi $M$ perechi de numere $(x, y)$ $(1 <= N, M <= 100.000)$. Pentru fiecare pereche ordonată de indici $(x, y)$ trebuie determinată subsecvenţa de sumă maximă a subşirului $a{~x~}, a{~x+1~}, ..., a{~y~}$. Subsecvenţele alese trebuie să conţină cel puţin un element.
h3. Exemplu:
h3. Rezolvare:
Putem obţine un algoritm de complexitate $O(M * N)$ folosind algoritmii liniari din prima problemă, dar să vedem cum putem reduce complexitatea folosind alte abordări. Mai întâi calculăm şirul $sum[]$ al sumelor parţiale, după care împărţim şirul în $K$ subsecvenţe de lungimi egale $[N / K]$, şi păstrăm următoarele informaţii pentru fiecare din ele:
Putem obţine un algoritm de complexitate $O(M * N)$ folosind algoritmii liniari din prima problemă, dar să vedem cum putem reduce complexitatea folosind alte abordări. Mai întâi calculăm şirul $sum$ al sumelor parţiale, după care împărţim şirul în $k$ subsecvenţe de lungimi egale $[n / k]$, şi păstrăm următoarele informaţii pentru fiecare din ele:
* $max[i]$ - cea mai mare valoare $sum[j]$, unde: $N/K * (i - 1) < j <= N/K * i$;
* $max[i]$ - cea mai mare valoare $sum[j]$, unde: $n/k * (i-1) < j <= n/k * i$;
* $min[i]$ - cel mai mic $sum[j - 1]$, unde: $N/K * (i - 1) < j <= N/K * i$;
* $min[i]$ - cel mai mic $sum[j-1]$, unde: $n/k * (i-1) < j <= n/k * i$;
* $best[i]$ - valoarea subsecventei de suma maxima a secventei curente.
Acum, pentru a afla subsecvenţa de sumă maximă a subsecvenţei $a[x..y]$ studiem cele două cazuri posibile:
1. Dacă elementele de indice $x$ şi $y$ aparţin aceleiaşi subsecvenţe, atunci putem găsi ceea ce căutăm folosind algoritmul liniar direct pe şirul $a[x..y]$. Complexitate: $O(N/K)$.
1. Dacă elementele de indice $x$ şi $y$ aparţin aceleiaşi subsecvenţe, atunci putem găsi ceea ce căutăm folosind algoritmul liniar direct pe şirul $a[x..y]$ (complexitate $O(n/k)$).
2. Dacă nu sunt în aceeaşi secvenţă, atunci vom împărţi şirul $a[x..y]$ în:
* zero sau mai multe subsecvenţe complete ce aparţin partiţionării,
după care rezolvăm problema pentru sufix şi prefix prin metoda liniară în $O(N/K)$, şi determinăm în $O(1)$ pentru fiecare bucată în care este spart şirul $a[x..y]$ subsecvenţa ei de sumă maximă.
după care rezolvăm problema pentru sufix şi prefix prin metoda liniară în $O(n/k)$, şi determinăm în $O(1)$ pentru fiecare bucată în care este spart şirul $a[x..y]$ subsecvenţa ei de sumă maximă.
Mai rămâne să găsim subsecvenţa de sumă maximă cu capătul în bucăţi diferite. Pentru două bucăţi fixate $i < j$, subsecvenţa de sumă maximă ce are câte un capăt în fiecare bucată are valoarea: $max[j] - min[i]$. Determinarea subsecvenţei de sumă maximă cu capetele în bucăţi diferite devine astfel de complexitate $O(K)$. Deci, pentru a rezolva o întrebare trebuie să facem $O(N/K + K)$ calcule. Pentru a reduce complexitatea problemei considerăm pe $K = sqrt(N)$. Complexitatea totală a acestei soluţii este $O(N + M sqrt(N))$.
Mai rămâne să găsim subsecvenţa de sumă maximă cu capătul în bucăţi diferite. Pentru două bucăţi fixate $i <= j$, subsecvenţa de sumă maximă ce are câte un capăt în fiecare bucatăm are valoarea $max[j] - min[i]$. Determinarea subsecvenţei de sumă maximă cu capetele în bucăţi diferite devine astfel de complexitate $O(k)$. Deci pentru a rezolva o întrebare trebuie să facem $O(n/k + k)$ calcule. Pentru a reduce complexitatea problemei considerăm pe $k = sqrt(n)$. Complexitatea totală a acestei soluţii este $O(N + M sqrt(N))$.
Să vedem ce se întâmplă pe exemplu:
|_. $min$ | $-1$ | $2$ | $8$ |
|_. $best$ | $5$ | $4$ | $8$ |
Pentru a răspunde la întrebarea $[1, 5]$ trebuie să răspundem la cele două subsecvenţe componente $[1..3]$ şi $[4..5]$. Soluţia optimă pentru $[1..3]$ este $best[&#49;] = 5$. Soluţia optimă pentru $[4..5]$ o determinăm folosind algoritmul liniar, ea fiind $4$. Acum, pentru a determina subsecvenţa de sumă maximă cu câte un capăt în fiecare interval folosim formula: $max(sum[i]) - min(sum[j - 1])$, unde $4 <= i <= 5$ şi $1 <= j <= 3$. Valoarea $max(sum[i])$ o găsim parcurgând intervalul $[4, 5]$ ca fiind $6$, iar valoarea $min(sum[j - 1])$ o avem deja calculată în $min[&#49;]$. De aici obţinem rezultatul $7$.
Pentru a răspunde la întrebarea $[1, 5]$ trebuie să răspundem la cele două subsecvenţe componente $[1..3]$ şi $[4..5]$. Soluţia optimă pentru $[1..3]$ este $best[&#49;] = 5$. Soluţia optimă pentru $[4..5]$ o determinăm folosind algoritmul liniar, ea fiind $4$. Acum, pentru a determina subsecvenţa de sumă maximă cu câte un capăt în fiecare interval folosim formula $max(sum[i]) - min(sum[j-1])$, unde $4 <= i <= 5$ şi $1 <= j <= 3$. Valoarea $max(sum[i])$ o găsim parcurgând intervalul $[4, 5]$ ca fiind $6$, iar valoarea $min(sum[j-1])$ o avem deja calculată în $min[&#49;]$. De aici obţinem rezultatul $7$.
O soluţie similară poate fi obţinută cu ajutorul arborilor de intervale. Mai întâi creăm arborele de intervale. Pentru fiecare interval aflăm elementele $min$, $max$ şi $best$ astfel:
h2(#prob4). Problema 4 (ACM ICPC NWERC 97, olimpiada online 2000, campion 2001)
bq. Se dă un şir $(a{~1~}, a{~2~}, ..., a{~N~})$ format din numere întregi. Se cere să se determine subsecvenţa $a[i..j]$ care are modulul sumei elementelor minim.
Se dă un şir $(a{~1~}, a{~2~}, ..., a{~N~})$ format din numere întregi. Se cere să se determine subsecvenţa $a[i..j]$ care are modulul sumei elementelor minim.
h3. Exemplu:
h3. Rezolvare:
Construim întâi şirul sumelor parţiale. Pentru oricare două elemente $sum[i]$ şi $sum[j]$ cu $(i != j)$ modulul sumei unei subsecvenţe din şir va fi $|sum[i] - sum[j]|$. Dacă $i < j$, atunci secvenţa va fi $a[i+1..j]$, iar dacă $j < i$, atunci secvenţa va fi $a[j+1 .. i]$. Astfel, pentru a găsi subsecvenţa de modul minim trebuie, de fapt, să găsim perechea de indici $i$ şi $j$ astfel ca $|sum[i] - sum[j]|$ să fie minim. Sortând şirul sumelor parţiale şi luând o pereche de indici $i < j$, atunci $sum[i] < sum[j]$, iar $|sum[j] - sum[i]| = sum[j] - sum[i]$. Pentru a găsi perechea $(i, j)$ pentru care $i < j$ şi $sum[j] - sum[i]$ este minim, trebuie ca $i$ să fie egal cu $j + 1$. Astfel obţinem un algoritm de complexitate $O(N log N)$.
Facem mai întâi şirul sumelor parţiale. Pentru oricare două elemente $sum[i]$ şi $sum[j]$ cu $(i != j)$ modulul sumei unei subsecvenţe din şir va fi $|sum[i] - sum[j]|$. Dacă $i < j$, atunci secvenţa va fi $a[i+1..j]$, iar dacă $j < i$, atunci secvenţa va fi $a[j+1 .. i]$. Astfel, pentru a găsi subsecvenţa de modul minim trebuie, de fapt, să găsim perechea de indici $i$ şi $j$ astfel ca $|sum[i] - sum[j]|$ să fie minim. Sortând şirul sumelor parţiale şi luând o pereche de indici $i < j$, atunci $sum[i] < sum[j]$, iar $|sum[j] - sum[i]| = sum[j] - sum[i]$. Pentru a găsi perechea $(i, j)$ pentru care $i < j$ şi $sum[j] - sum[i]$ este minim, trebuie ca $i$ să fie egal cu $j + 1$. Astfel obţinem un algoritm de complexitate $O(N log N)$.
Să vedem cum merge pe exemplul prezentat:
h2(#prob5). Problema 5 (USACO)
bq. Se dă un şir $(a{~1~}, a{~2~}, ..., a{~N~})$ format din $N (1 <= N <= 100 000)$ numere întregi $(1 <= a{~i~} <= 2 000)$ si un numar natural $F$. Se cere să se determine subsecvenţa $a[i..i + K - 1]$ cu media aritmetică a elementelor maximă, unde $K$ are proprietatea $K >= F$.
Se dă un şir $(a{~1~}, a{~2~}, ..., a{~N~})$ format din $N (1 <= N <= 100 000)$ numere întregi $(1 <= a{~i~} <= 2 000)$. Se cere să se determine subsecvenţa $a[i..i + K - 1]$ cu media aritmetică a elementelor maximă $(K >= F, 1 <= F <= N)$.
h3. Exemplu:
h2(#prob6). Problema 6 ('Secvenţă':problema/secventa)
bq. Se da un şir de $N$ numere întregi. O secvenţă este un subşir de numere care apar pe poziţii consecutive în şirul iniţial. Definim baza unei secvenţe ca fiind minimul valorilor elementelor din secvenţa respectivă. Fiind dat un număr natural $K$, determinaţi o secvenţă de lungime cel puţin $K$, cu baza maximă. Restrictii: $1 <= K <= N <= 500 000$.
Gigel are un şir de $N$ numere întregi. Toată lumea ştie că o secvenţă este un subşir de numere care apar pe poziţii consecutive în şirul iniţial. Gigel a definit baza unei secvenţe ca fiind minimul valorilor elementelor din secvenţa respectivă. Fiind dat un număr natural $K$, determinaţi pentru Gigel o secvenţă de lungime cel puţin $K$, cu baza maximă. $(1 <= K <= N <= 500 000)$
h3. Exemplu:

Nu exista diferente intre securitate.

Topicul de forum nu a fost schimbat.