Суб67це
Аутор: Василије Новаковић
Текст и тест примери: Василије Новаковић
Анализа решења: Василије Новаковић
Тестирање: Милош Милутиновић
За почетак размислимо како би смо за потпуно познату ниску (без упитника), израчунали трулост на спор начин.
Назовимо подниску трулом, ако је дужине 2 и први карактер је 6 а други 7 (трулост ниске је број њених трулих подниски)
Можемо избројати колико трулих подниски постоји, које почињу неким конкретним каркатером на позицији i.
Ако важи s_i = 7, тад постоји 0 трулих подниски којима је први каркатер i, а ако је s_i = 6, тад је број трулих подниски које почињу на тој позицији, једнак броју позиција j, j \gt i, s_j = 7.
Тада је трулост ниске управо једнака суми трулих подниски које почињу на позиији i, 1 \leq i \leq N.
Приметимо одавде да нам је само битно за сваку шестицу, колико има седмица након ње.
Подзадазак 1: сви карактери ниске су ‘?’
Приметимо да је оптимално да све упитнике које заменимо у 6, ставимо пре свих упитника које заменимо у 7.
Назовимо позицију последњег упитника који ћемо променити у шестицу “граница упитника”.
Доказ за ово је једноставан: ако постоје два упитника, који су замењени за 7 и 6, тако да се седмица налази пре шестице, онда посматрајући начин на који рачунамо трулост ниске, можемо приметити да ако заменимо уместо тога први упитник у 6 а други у 7, трулост ће се сигурно повећати барем за 1, и никад се неће смањити.
Дакле, за било које две позиције на којима су упитници, и заменили смо први у 7 и други у 6, увек можемо повећати трулост тако што им заменимо вредности, а кад не постоје овакви парови, то значи да се све шестице налазе пре свих седмица.
Након што је установљено да ћемо неки префикс упитника претворити у 6 а остале вредности у 7, треба узети оптималан распоред.
Формалније, рецимо да одговарамо на упит од L до R. Пошто су у овом подзадатку све упитници, то значи да одговарамо на упит са x = R - L + 1 упитника.
Ако заменимо A упитника у 6, а B упитника у 7, тада важи A + B = x, а трулост је једнака производу A \cdot B
Поприлично је интуитивно, али се може и доказати помоћу неједнакости за аритметичку и геометријску средину, да ћемо прву половину заменити у шестице, а другу половину у седмице, а ако x није дељив са 2, није битно да ли ћемо број у средини заменити у 6 или 7, јер ће резултат бити исти.
Временска сложеност О(1) по упиту.
Укупна временска сложеност је О(N+Q)
Просторна сложеност О(N)
Позадатак 2: N, Q \leq 100
У овом подзадатку можемо искористити обзервацију из претходног, а то је да ћемо неки префикс упитника заменити са 6, а остале упитнике са 7.
Можемо фиксирати границу где ће нам шестице престати, то јест седмице почети, и за тако добијену ниску израчунати трулост на начин описан у почетку задатка.
Сад се своди на израчунавање трулости фиксиране ниске (без упитника), што овај подзадатак дозвољава у О(N^2), иако је могуће урадити то значајно брже.
Сложеност: O(N^3 \cdot Q)
Просторна сложеност О(N)
Подзадатак 3: N, Q \leq 500
Овај подзадатак можемо урадити исто као и претходни, само што ћемо за фиксну границу трулост израчунати брже, у O(N), што доводи финалну сложеност на O(N^2 \cdot Q).
Просторна сложеност О(N)
Подзадатак 4: ни један карактер није ‘?’
У овом подзадатку је потребно брзо одговарати на упите, али нам је цела ниска већ фиксна.
Прво нађимо начин да брзо одговарамо на упите где је L = 1:
Можемо израчунати низ prefAns, где је prefAns_i једнак одговору на упит L = 1, R = i.
Овај низ можемо лако израчунати у О(N), користећи идеју из претходног подзадатка.
Сад разматрамо како да нађемо трулост од L до R, користећи овај низ:
Ако узмемо само prefAns_R, избројаћемо више него што треба, јер ће шестице које се налазе пре позиције L, да додају на трулост.
Свака шестица која се налази пре позиције L ће додати на трулост број седмица између њене позиције и позиције R. Ово се даље може разложити на број седмица између њене позиције и L-1 + број седмица између позиција L и R. Кад посматрамо све шестице заједно и групишемо први члан то је заправо prefAns_{L-1}, док је други члан заправо производ броја шестица од 1 до L-1 и броја седмица од L до R. Број шестица и седмица можемо наћи користећи одвојене префиксне суме, али коначна формула за одговор на упит од L dо R је:
- prefAns_R - prefAns_{L-1} - cnt6[1:L-1] \cdot cnt7[L:R]
Временска сложеност О(N + Q)
Просторна сложеност О(N)
Подзадатак 5: N, Q \leq 2000
Користећи идеју из претходног подзадатка, најлакше решење за овај подзадатак је да фиксирамо границу где престајемо упитнике да претварамо у 6, и почињемо да их претварамо у 7, независно од упита, и да израчунамо оне исте низове за сваку од тих граница, којих има највише N.
Након што то урадимо, одговор на упит може да се ради на исти начин, тако што фиксирамо границу и узмемо максимални одговор по свакој граници за неки упит, јер одговор можемо да нађемо у O(1).
Временска сложеност О(N \cdot (N + Q)).
Просторна сложеност О(N^2)
Подзадатак 6: L_i = 1
У овом подзадатку се сваки упит ради на префиксу ниске.
Можемо сортирати упите по R и одговарати на њих offline.
Приметимо да како десна граница упита расте, наша граница где престајемо да стављамо шестице никако не може да се смањи, може само да се повећава или да остане иста.
Доказ: замислимо да се десна граница повећава један по један карактер, а да је тренутна граница на којој престајемо да стављамо 6 и крећемо да стављамо 7 једнака x. Ако нам се сад десна граница упита повећа са један, то значи да је нови карактер који смо добили или 6 или 7 или ?. Ако је карактер 6, он не може да утиче на одговор јер је последњи, па не постоји ни једна седмица после њега. Дакле довољно је решити случај где је 7, јер ако је упитник сигурно ћемо га заменити за 7.
Ако је последњи карактер 7, то значи да ће допринос шестица које су лево да се повећа, што значи да сигурно није оптимално смањити број шестица сад, јер би у супротном било оптимално и за претходну границу.
Ово нам може дати интуицију како ће се трулост понашати кад померамо границу упитника.
Може се доказати да ће померањем границе упитника десно, трулост прво strogo да расте, па да достигне максимум, и више граница може да даје максималну трулост (што се може видети на примеру ???), али ће оне бити једна до друге, и након максимума ће strogo да опада.
Доказ је следећи:
Посматрајмо како се трулост мења кад границу померимо са i-1-ог на i-ти упитник (претворимо i-ти упитник у 6 уместо у 7).
Трулост ће се смањити за број шестица пре тог упитника (упитнике пре тог сматрамо за шестице такође), али повећати за број седмица након њега (упитнике након сматрамо за седмице).
Како померамо границу на десно, број шестица лево ће да расте бар за 1, а број седмица ће се смањити бар за 1 (јер смо баш тај конкретан упитник управо претворили са 7 у 6, па кад се померимо још на десно сигурно ће се повећати број шестица за барем 1, исто тако кад се пребацимо на следећи упитник, он је пре пребацивања био 7, а сад посматрамо све десно од њега, па нам се број седмица смањио бар за 1).
Ово значи да ће фактор који се одузима да расте, док ће фактор који се додаје да се смањује, и једини случај кад трулост остаје иста, је кад су та два фактора једнака (што не мора да се деси), што је сигурно максимум јер је пре тога фактор који се одузима сигурно био мањи од фактора који повећава, а након тога је фактор који се одузима сигурно већи па ће трулост да настави строго да опада.
Знајући ово, како нам се десна граница упита помера у десно, можемо да померамо нашу границу упитника све док трулост расте.
Како би брзо израчунали трулост за одређену границу, треба имати додатно израчунато и:
- укупан број седмица након сваког упитника који се налази у првих i позиција: prefq7[i]
- укупан број шестица који се налази пре сваког упитника, у последњих i позиција: sufq6[i]
Након тога је могуће за неку границу x израчунати трулост тако што је поделимо збир следећих делова:
-
Колико свака шестица има седмица након себе (рачунамо исто као у четвртом подзадатку)
-
Производ броја упитника које претварамо у шестица и броја упитника које претварамо у седмице.
-
Колико укупно има седмица након свих упитника које претварамо у шестице.
-
Колико укупно има шестица пре свих упитника које претварамо у седмице.
Сваки од ових бројева је могуће израчунати у О(1) за неку дату границу, након што смо претходно поменуте низове израчунали пре свих упита.
Временска сложеност: O(N + Q \cdot log(Q))
Просторна сложеност: О(N + Q)
Решење без додатних ограничења
Користећи конкавност функције трулости у зависности од границе упитника, можемо доћи на идеју да радимо за сваки упит бинарну претрагу по граници упитиника.
Израчунаћемо трулост за две суседне границе упитника:
- Ако је трулост једнака за обе границе, то значи да нам та граница даје максималну трулост
- Ако је трулост већа за другу границу, то значи да трулост још расте након испитане границе, па можемо отићи у десну половину претраге.
- Ако је трулост мања за другу границу, то значи да ће само још више да опада након испитане границе, па треба отићи у леву половину претраге.
За начин рачунања трулости у зависности од границе, погледати претходни подзадатак.
Временска сложеност: O(N + Q \cdot log(N)).
Просторна сложеност: О(N).