Алтруизам
Аутор: Никола Милосављевић
Текст и тест примери: Никола Милосављевић
Анализа решења: Никола Милосављевић
Тестирање: Алекса Милисављевић
Анализа
Означимо са S_i(n) збир i-тих степена цифара броја n (нпр. S_3(2021)=2^3+0^3+2^3+1^3=17). Потребно је пронаћи природан број n из сегмента [x,y] за који важи
n = a_1 \cdot S_1(n)+a_2\cdot S_2(n) + \ldots + a_k \cdot S_k(n)
Најједноставније решење је проверити претходну једнакост за сваки број из [x,y]; директна имплементација ради у сложености O(|y-x|\cdot k) и решава подзадатак 1.
Мало боље решење (које води коначном решењу) је записати претходну једначину на другачији начин. За сваку цифру i, 1 \leq i \leq 9 уведимо ознаку c_i = a_1 \cdot i^1 + a_2\cdot i^2 + \ldots + a_k \cdot i^k. Такође, означимо број појављивања цифре i (1\leq i \leq 9) у броју n са x_i(n). Није тешко уочити да је полазна једначина еквивалентна са
n = c_1 \cdot x_1(n) + c_2 \cdot x_2(n) + \ldots + c_9 \cdot x_9(n)
За конкретан број n претходну једначину можемо проверити у O(\log n) (број цифара броја n) па долазимо до решења сложености O(|y-x|\log y) које је довољно за подзадатак 2.
У подзадатку 3 је k \leq 2; како је n \leq 10^{18}, важи S_1(n) \leq 9\cdot 18 = 162 и S_2(n)\leq 9^2 \cdot 18 = 1458 па можемо испробати свих 162 \cdot 1458 могућности за ове вредности и проверити да ли добијени број n задовољава једначину.
Приметимо да ако n садржи бар једну цифру вредности c, тада важи n \geq c^1+c^2+\ldots +c^k. Сада, из n \leq 10^{18}, добијамо да ако n садржи бар једну цифру већу од 1 мора важити да је k \leq 58. Како у подзадатку 4 важи k = 2021, следи да су у овом подзадатку једини кандидати за решење бројеви који се састоје од нула и јединица. Сада на основу друге једначине имамо n = c_1 \cdot x_1(n) па једноставно испробамо свих 18 могућих вредности за x_1(n) (или, мало компликованије, генеришемо свих 2^{18} - 1 таквих бројева и проверимо их).
Кључно запажање, које директно следи из једначине са c_i-овима, је да бројеви са истим бројем појављивања сваке не-нула цифре дају исту вредност са десне стране једначине (нпр. 35502, 2355, 5532, 20305050...) па проверу не морамо вршити по свим бројевима из [x,y] већ по броју појављивања цифара. Довољно је испробати све 9-орке (x_1, x_2, ..., x_n) ненегативних целих бројева за које је 1 \leq x_1 + x_2 + \ldots +x_9 \leq 18 (број цифара је између 1 и 18), израчунати десну страну једначине и проверити да ли је добијени број n из [x,y] и да ли се у њему свака цифра i јавља тачно x_i пута.
За генерисање оваквих 9-орки користимо backtracking технику. Један од начина је заправо генерисати бројеве са нерастућим низом цифара: са F(a,b) oзначимо позив рекурзивне функције у коме треба фиксирати a-ту цифру при чему је претходна цифра b; рекурзивни позиви су F(a+1, b) (a-та цифра је b, уз повећање x_b) и F(a, b-1) (a-та цифра је мања од b) . Број поменутих деветорки се може одредити покретањем овог алгоритма или користећи мало комбинаторике; тај број је \binom{27}{9}-1=4686825 тј. довољно је мали да овај алгоритам решава цео задатак у задатом временском ограничењу.