[Rešenja zadataka] 2021/2022 Kvalifikacije - Drugi krug

Мађионичар

Аутор: Павле Мартиновић
Текст и тест примери: Павле Мартиновић
Тестирање: Владимир Миловановић
Анализа решења: Владимир Миловановић

Главно решење

Пошто је у задатку позната карта (односно њена вредност K) која се налази директно изнад тражене карте, ако се шпил карата посматра као низ позитивних целобројних вредности, то ће другим речима значити, да је поставком задатка дата вредност у низу под индексом за један мањим у односу на индекс захтеване вредности. Стога је у првом кораку потребно пронаћи индекс i у низу под којим је записана дата вредност K, а затим у наредним кораку исписати вредност под индексом i+1. Како би се освојили сви поени, неопходно је обратити пажњу на један специјалан случај, који је објашњен у другом јавном примеру у поставци задатка, а то је када је i=N. У овом случају индекс тражене карте није i+1, односно N+1, из разлога што он не постоји, већ је то прва карта у шпилу, односно вредност под индексом i=1, уз претпоставку да индексе рачунамо почевши од јединице, а не од нуле. Елегантан начин да се покрије овај изузетак јесте узети i+1 и пронаћи остатак при дељењу са N, то јест индекс тражене вредности ће бити (i+1) \mod N и све што треба урадити у задатку након учитавања одговарајућих података је испис вредности под поменутим индексом.

Како се у најгорем случају вредност низа K може налазити под индексом N, неопходно је у горе описаном првом кораку проћи кроз читав низ да би се то утврдило, па је асимптотска временска сложеност алгоритма \mathcal{O}(N), односно линеарна по дужини низа.

Екскурзија

Аутор: Алекса Плавшић
Текст и тест примери: Алекса Плавшић
Тестирање: Алекса Милисављевић
Анализа решења: Драган Урошевић

Решење кад N = 3

У овом случају, број група не може бити већи од 3. Према томе, потребно је само одредити минимални број бананица за све три вредности за број група. Ако је K=1, онда у тој групи има 3 ученика, минимални број бананица је 1+2+3=6. Ако је K=2, онда у једној групи морају бити два ученика (и минималан број бананица је 1+2=3), а у другој групи 1 ученик (и минималан број бананица је 1), па је укупан минималан број бананица 4. Ако је K=3, онда је у свакој групи 1 ученик, па је укупан минималан број бананица 3.

Решење кад K = 1

У овом случају, сви ученици су у истој групи и минималан број бананица је

1+2+3+\dotsb + N = \frac{N\cdot(N+1)}{2}.

Потребно је водити рачуна да последњи производ може бити врло велики број.

Решење кад N, M \leq 10

У овом случају, до решења се може доћи применом претраге са враћањем (бектрек).

Решење кад N \leq 2000

У овом случају се примењује главно решење у којем не приметимо све формуле, већ примењујемо неке мање ефикасне методе (нпр. пролазак кроз све групе).

Главно решење

Потребно је приметити да групе треба да буду приближно једнаке величине. Наиме, ако је c_1 број ученика у једној групи, c_2 број ученика у другој групи и при томе важи c_2 \geq c_1 + 2, онда је минимални број бананица за те две групе

B_1 = \frac{c_1\cdot(c_1+1)}{2} + \frac{c_2\cdot (c_2+1)}{2} = \frac{c_1^2+c_2^2+c_1+c_2}{2}.

Ако једног ученика пребацимо из друге групе у прву групу, онда је минимални број бананица у те две групе

B_2 = \frac{(c_1+1)\cdot(c_1+2)}{2} + \frac{(c_2-1)\cdot c_2}{2} = \frac{c_1^2+c_2^2+3c_1-c_2+2}{2}.

Разлика два последња броја је

B_1 - B_2 = \frac{2c_2 - 2c_1 - 2}{2} = c_2 - c_1 -1 > 0,

тј. минималан број бананица се смањио.

Према томе, све групе треба да имају приближно једнако елемената. Ако је број ученика дељив бројем група, онда би свака група имала N/K ученика. Ако број ученика није дељив бројем група онда ће један део група имати N_1 = \lfloor N/K \rfloor, а други део група N_2 = N_1 + 1. Број група K_2 које имају N_2 ученика је

K_2 = N - K \cdot \lfloor N/K\rfloor = N \text{ mod } K,

где је N \text{ mod } K остатак при дељењу броја N бројем K.
Коначно, минималан укупан број бананица је

(K-K_2) \cdot \frac{N_1\cdot (N_1+1)}{2} + K_2 \cdot \frac{N_2\cdot (N_2+1)}{2}.

Сложеност алгоритма је O(1).

Палиндром шафл

Аутор: Алекса Плавшић
Текст и тест примери: Алекса Плавшић
Тестирање: Алекса Милисављевић
Анализа решења: Лазар Миленковић

Са N ћемо означити дужину дате ниске, са \Sigma број карактера у алфабету, у нашем случају 26.

Решење када су два слова ‘b’, а остала ‘а’

Оптимално решење у овом случају је или померити оба слова на два централна поља или померити једно слово на позицију симетричну позицији другог слова.

Решење када N \leq 50

Задатак можемо решити тако што претпоставимо леву и десну границу оптималне подниске, i и j, респективно (број могућности је \Theta(N^2)). За сваку могућност (i,j), у линеарном времену проверимо да ли је могуће извршити шафл тако да је резултујућа ниска палиндром. Посматрамо интервал [i,j] и симетрични интервал [n-j+1, n-i+1]. Уколико изван ова два интервала, улазна ниска није палиндромска, тада је немогуће променити било шта у [i,j] тако да решење постане палиндром. Другим речима, претпоставка [i,j] није валидна. У супротном, када интервал [i,j] не садржи средину ниске, довољно је проверити да за свако слово важи да je његова учестаност у [i,j] иста као и његова учестаност у [N-j+1, N-i+1]. Када [i,j] садржи средину ниске, провера је слична, само у обзир треба узети и преклапања интервала [i,j] и [N-j+1, N-i+1].

Решење када N \leq 3000

Претходна идеја се може убрзати ако приметимо да када фиксирамо два краја проверу можемо извршити у временској сложености O(\Sigma).

Главно решење

Посматрајмо најпре највећи број l, такав да је префикс ниске дужине l једнак суфиксу дужине l у обрнутом редоследу. Оптимално решење никада неће садржати првих l и последњих l слова ниске. Најпре ћемо проверити да ли је могуће извршити шафл на само левој половини ниске. То проверавамо тако што тражимо најмањи индекс i_1 \le |T|/2 такав да за свако слово важи да је његова учестаност у интервалу [l+1,i_1] истa као и његова учестаност у интервалу [N-i_1+1, N-l] и да је улазна ниска палиндром у интервалу [i_1, N-i_1]. Уколико такав индекс постоји кандидат за решење је интервал [l,i_1].

У наставку ћемо претпоставити да оптимално решење садржи средишњи део ниске и почиње од индекса l+1. (Пошто су по дефиницији вредности l слова у нисци на позицијама l+1 и N-l различита, оптимална подниска мора увек садржати бар једну од ове две позиције. У имплементацији је потребно проверити оба случаја појединачно.) Тражимо најмањи индекс i_2 > N/2 такав да за свако слово важи да је његова учестаност у интервалу [i_2+1, N-l] мања или једнака његовој учестаности у интервалу [l+1, i_2]. Уколико такав индекс постоји, кандидат за решење је интервал [l+1, i_2]. Ово можемо гарантовати, јер нам се гарантује да ће постојати такав интервал. Из тога можемо закључити да ће и ,централни део’’ моћи да се испремешта да буде палиндром.

Учесестаност слова у интервалима можемо одредити коришћењем префиксних сума и описано решење је могуће имплементирати у временској сложености од O(N \cdot \Sigma). Мало пажљивија имплементација даје временску сложеност од O(N). Постоје и алтернативна решења задатка која користе бинарну претрагу или претраживачка стабла и раде у сложености O(N \log N), што је такође довољно за све поене на овом задатку.

Гуштер

Аутор: Андреј Ивашковић
Текст и тест примери: Андреј Ивашковић
Тестирање: Алекса Милисављевић
Анализа решења: Андреј Ивашковић

Овај задатак се решава динамичким програмирањем, што се види по томе што је реч о оптимизацији и по томе што наћи оптимално решење за дати улаз зависи од оптималних решења за подниске тог улаза.

Основа решења за три подзадатка је иста: добити 50 или 100 поена на овом задатку захтева да се примете. Нека је n дужина дате ниске s (индексиране од нуле).

Решење за n \leq 100

Дефинишимо дводимензиони низ \mathit{dp} формата (n+1)\times(n+1):

  • \mathit{dp}[i][j] за i,j>0: оптималан змија-скор који суфикс ниске s дужине i може да оствари, уколико се у првог реду логотипа налази j знакова; ако не постоји ниједан такав дозвољен логотип, -\infty;
  • \mathit{dp}[i][0] и \mathit{dp}[0][j] могу да се игноришу и немају никакво посебно значење.

Уколико знамо све вредности \mathit{dp}[i][j], тада је решење једнако \max_{2 \leq j \leq n} \{\mathit{dp}[n][j]\}: оптимално решење садржи било који (дозвољен) број симбола у првом реду.

Најпре приметимо неке основне чињенице о \mathit{dp}[i][j] које служе као темељ одређивања коначног решења:

  • \mathit{dp}[i][i] = 0, реч је о решењу у ком цео логотип за суфикс дужине i стаје у један ред;
  • \mathit{dp}[i][j] = -\infty за i<j;
  • \mathit{dp}[i][1] = -\infty (није могуће да у било ком реду буде само један знак).

За даље рачунање се ослањамо на наредно запажање:

Ако суфикс ниске s дужине i садржи j знакова (1<j<i), оптималан змија-скор који може да се оствари је највећи од свих збирова \mathit{dp}[i-j][k] и броја поклапања знакова уколико се у првом реду налази j, а у другом i знакова.

Број поклапања може да се израчуна провером да ли се поклапају знаци s на позицијама n-i+j+p-1 и n-i+j-p, при чему се p мења. Ако дефинишемо P(t,p) као индикатор да ли се ови знаци на позицијама n-t+p-1 и n-t-p поклапају (дакле 0 или 1; 0 је одговор и у случају да је један од ових знакова ван опсега ниске), претходна чињеница може да се запише у виду наредне рекурентне везе:

\mathit{dp}[i][j] = \max_{2<k\leq i-j} \{\mathit{dp}[i-j][k] + \sum_{p=1}^{\min(j,k)} P(i-j,p)\}

Све вредности \mathit{dp}[i][j] могу да се одреде пратећи ову формулу.
У псеудокоду, овако изгледа главни део алгоритма:

for i in 1 .. n:
    for j in 2 .. i:
        dp[i][j] = -∞
        for k in 2 .. j:
            broj_poklapanja = 0
            for p in 1 .. min(j, k):
                broj_poklapanja += P(i - j, p)
            dp[i][j] = max(dp[i][j], dp[i - j][k] + broj_poklapanja)

Коначна временска сложеност је O(n^4), а меморијска O(n^2).

Решење за n \leq 500

У овом случају потребно је приметити да при одређивању \mathit{dp}[i][j] и \mathit{dp}[i][j+1] треба да водимо рачуна о наредне две суме:

  • \sum_{p=1}^{\min(j,k)} P(i-j,p);
  • \sum_{p=1}^{\min(j,k+1)} P(i-j,p)
    а њихова разлика је или 0 или последњи сабирак у збиру: P(i-j,k+1).

Претходно решење стога може да се упрости тиме што се променљива broj_poklapanja ажурира сваки пут када се ажурира k. Имплементација се мења на следећи начин:

for i in 1 .. n:
    for j in 2 .. i:
        dp[i][j] = -∞
        broj_poklapanja = P(i - j, 1)
        for k in 2 .. j:
            if k <= j:
                broj_poklapanja += P(i - j, k)
            dp[i][j] = max(dp[i][j], dp[i - j][k] + broj_poklapanja)

Резултујућа сложеност је O(n^3), а меморијска O(n^2).

Главно решење

Решење за свих 100 поена ради у временској сложености O(n^2) и заснива се на избегавању понављања непотребног рада.

Приметимо да у решењу претходног подзадатка имамо итерације по j и по k, које одређују дужине два узастопна реда.
Како се ажурира j, мења се последњи знак у првом реду и први знак у другом реду, као и подаци о свим поклапањима.
Стога у оптимизованом решењу желимо да искористимо исте податке о поклапањима што је могуће дуже тако што ће спољна итерација бити по положају последњег знака првог реда.
Суфиксу дужине z+d, у ком први ред има дужину d, први ред се завршава знаком са индексом n-z-1 и други ред почиње знаком са индексом n-z – спољна итерација је по z, унутрашња по d.

За добијање коначног решења неопходно је посматрати шта се дешава у случају два суседна реда у логотипу уколико други ред починје знаком са индексом n-z. Претпоставимо да први ред има дужину d.

  • Ако је први ред краћи од другог, број знакова који се поклапају је једнак \sum_{p=1}^{d} P(i-j,p).
    Дакле, једино је питање одредити неко k \geq d тако да је \mathit{dp}[z][k] максимизовано.
  • Ако је први ред дужи од или једнаке дужине као и други, тада нас међу свим \mathit{dp}[z][k]+\sum_{p=1}^{k} P(i-j,p) за које је k\leq d занима оно највеће.

У првом случају је довољно увести матрицу m дефинисану на следећи начин:

  • m[i][j] = \max_{j\leq k\leq i}\{\mathit{dp}[i][k]\} за j \leq i

која може да се израчуна помоћу рекурентне везе:

  • m[i][i] = \mathit{dp}[i][i] = 0;
  • m[i][j] = \max\{\mathit{dp}[i][j],m[i][j+1]\}, за 0\leq j<i.

У другом случају радимо сличну ствар као у другом подзадатку: пратимо актуелно највеће \mathit{dp}[z][k] + \sum_{p=1}^{k} P(i-j,p) за све k\leq d.
То води наредном псеудокоду (изузев иницијализације):

for d in 2 .. n:
    broj_poklapanja[1] = P(i - j, 1)
    sufiks_max[d][d] = dp[d][d]
    poklapanje_plus_ostatak[0] = 0;
    for k in 1 .. d:
        sufiks_max[d][d - k] = max(sufiks_max[d][d - k + 1], dp[d][d - k]);
        poklapanje_plus_ostatak[k] = 0;
    for t in 2 .. min(d, n - d):
        broj_poklapanja[t] = broj_poklapanja[t - 1] + P(d, t);
        poklapanje_plus_ostatak[t] = broj_poklapanja[t] + dp[d][t];
        dp[d + t][t] = max(dp[d + t][t], sufiks_max[d][t] + broj_poklapanja[t]);
    max_zbir = 0;
    for j in 2 .. (n - d):
        if j <= d:
            max_do_sad = max(max_do_sad, poklapanje_plus_ostatak[j]);
        dp[d + j][j] = max(dp[d + j][j], max_do_sad);

За крај, поменимо да је могуће добити све поене чак и када се имплементира решење сложености O(n^2 \log n), под условом да је константа сакривена O-нотацијом довољно мала.
Једно овакво решење се заснива на идејама из прва два подзадатка, при чему се рачунање траженог минимума врши коришћењем сегментног стабла.
Међутим, решење временске сложености O(n^2) је краће и брже.

Чаробњак

Аутор: Алекса Милисављевић
Текст и тест примери: Алекса Милисављевић
Тестирање: Павле Мартиновић
Анализа решења: Алекса Милисављевић

Решење за N \leq 10

У овом случају можемо за сваки одабир K од N елемената испробати све могуће начине да извршимо операције. Временска сложеност је O({N \choose K} \cdot 2^K).

Решење за N \leq 200

У овом подзадатку до решења можемо доћи применом динамичког програмирања. Дефинишимо dp[l][r][p][g][h] на следећи начин:

  • За g=0, h=0 највећа вредност тако да у низу напитака остане напитак са том моћи, па онда напици из интервала [l,r] и да смо изван интервала одабрали да задржимо p елемената.
  • За g=0, h=1 најмања вредност тако да у низу напитака остане напитак са том моћи, па онда напици из интервала [l,r] и да смо изван интервала одабрали да задржимо p елемената.
  • За g=1, h=0 највећа вредност тако да у низу напитака остане напитак са том моћи, пре њега напици из интервала [l,r] и да смо изван интервала одабрали да задржимо p елемената.
  • За g=1, h=1 најмања вредност тако да у низу напитака остане напитак са том моћи, пре њега напици из интервала [l,r] и да смо изван интервала одабрали да задржимо p елемената.

Како се операцијама искључиво одузима вредност једног краја од вредности другог, то се проналажење максималне или минималне вредности на једном крају управо своди на проналажење минималне односно максималне вредности на супротном и примену једне операције. Ово динамичко програмирање је временске сложености O(N^3).

Решење за K = N

За решавање овог подзадатка, неопходно је приметити да су све вредности моћи напитка који остаје последњи у низу или разлика непразног префикса и одговарајућег непразног суфикса или разлика непразног суфикса и одговарајућег непразног префикса. За почетак, приметимо да моћ напитка који остаје последњи у низу увек можемо пресликати на низ b који садржи N вредности које су искључиво + или -. Конкретно, ако моћ неког напитка из почетног низа учествује са знаком + у моћи напитка који остаје последњи, на ту позицију у низу b стављамо +, а у супротном -. Посматрајмо сада низ b. Желимо да га сведемо на низ који има само један елемент и тај елемент има вредност +, применом операција дефинисаних у тексту. Приметимо да уколико прва и последња вредност у низу b имају исти знак, тада сигурно није могуће извршити ни једну операцију, јер тада желимо да и први и последњи елемент учествују са истим знаком, а знамо да применом било које од две операције доводимо до тога да у коначној суми учествују са различитим знаком. У супротном, можемо да извршимо било коју од ове две операције. На низу b ово се одржава брисањем једног од два краја. Дакле, уколико после примене неких операција дођемо до низа који има више од једног елемента и његови крајеви су различитог знака, онда нас тај низ никако не може довести до низа који садржи само један елемент +. Због тога није могуће да у низу b постоји више од једног пара суседних позиција које имају супротан знак. Дакле, довољно је да узмемо максимум разлика свих непразних префикса и одговарајућих непразних суфикса, односно непразних суфикса и одговарајућих непразних префикса. Ово је могуће урадити у временској сложености O(N).

Решење кад N \leq 1000

Решавање овог подзадатка се надовезује на решавање претходног. Фиксираћемо сваку позицију која ће представљати разлику између префикса и суфикса (односно суфикса и префикса) и потом избацити N-K елемената тако да се та разлика максимизује и да ни префикс ни суфикс не остану празни. Ово је могуће постићи сортирањем целог низа са промењеним знаком елемената у суфиксу, те избацивањем најмањих N-K елемената. Неопходно је само водити рачуна да избацивање тих елемената не доведе до празног префикса или суфикса. Овакво решење је временске сложености O(N^2 \log N).

Главно решење

За решење целог задатка, неопходно је оптимизовати решење претходног подзадатка тако да не морамо да за сваку позицију сортирамо низ и поново бирамо најмање елементе. Главна идеја у тој оптимизацији се заснива на томе да се променом позиције која раздваја префикс и суфикс за један мењају тачно две вредности из низа који сортирамо и из којег бирамо најмањих N-K. Можемо користити структуру set или сегментно стабло да би одржавали тај низ. Решење комплетног задатка је временске сложености O(N \log N).

2 Likes