Разборы → Meetup Contest #2: Разбор задачи E. Почти СНМ!

 
-1
 

Решается обычным СНМ-ом, но чуть модифицированным.

Итак, что нужно для решения задачи:

Прочитать про обычный СНМ. Ссылка - http://e-maxx.ru/algo/dsu

Теперь, что нужно для модифицированного СНМ-а:

  • Каждую вершину _i_ подвесить саму к себе

  • Для каждой вершины _i_ создать фиктивную вершину i'

  • Подвесить каждую i' к _i_

  • Теперь, во всех операциях(union, get_set, move) использовать только фиктивные вершины

Почему нужно работать только с фиктивными вершинами?

Потому, что к ним никогда ничто не подвешивается, из-за чего нам не надо перевешивать все ссылки потомков, когда если бы делали без фиктивных вершин, надо было бы перевешивать, а это долго.

Разборы → Meetup Contest #2: Разбор задачи D. Количество делителей

 
1
 

В этой задаче нам нужно уметь делать:

1 - Факторизацию числа

2 - Проверку числа на простоту

3 - Быстрое(бинарное) возведение в степень

#1 Факторизация числа – это представление числа в виде произведений простых чисел.

Пример: 100 = 2^2 * 5^2.

Теперь, если мы знаем факторизацию числа, то легко найти и количество его делителей.

Количество делителей равно произведению всех (степеней+1) в факторизации числа.

Если N = pr1^deg1 * pr2^deg2 * pr3^deg3 * … * prK^degK, то количество делителей равно (deg1 + 1) * (deg2 + 1) * (deg3 + 1) * … * (degK + 1), т.к. каждый множитель может входить в N со степенями от 0..deg_i.

Допустим N = 2^3 * 3^2 * 5^2, тогда количество делителей равно (3+1) * (2 + 1) * (2 + 1) = 36.

Обычная факторизация делается за O(√N).

Псевдокод:

Number_of_divisors = 1;
While (divisor^2 ≤ N)
{
    Deg = 0;
    While (N mod divisor = 0)
    {
        N /= divisor;
        Deg++;
    }
    Number_of_divisors *= Deg + 1;
}
If (N > 1)
    Number_of_divisors *= 2;

Единственная проблема в задаче – N большое число.

Т.к. обычная факторизация работает за O(√N), а у нас N ≤ 10^18 – то программа получит TLE

Что будем делать?

Модифицируем факторизацию до O(∛N). А именно будем перебирать делитель от 2 до ∛N, и делить пока делится. В один момент, когда divisor^3 > N, то останавливаемся и делаем вот что:

Т.к. divisor^3 > N, значит, N состоит из двух или одного множителя, больших divisor:

  1. Либо N – большое простое число, тут ответ умножается на 2

  2. Либо N = pr1 * pr2, тут ответ умножается на 4 (на 2 от первого и опять на 2 от второго)

  3. Либо N = x * x = x^2, тут ответ умножается на 3.

#2 Проверка числа на простоту:

Если N не такое уж большое, то можно перебрать все делители от 2 до √N, в противном случае воспользоваться приложением функции Эйлера, а именно:

Самое известное и важное свойство функции Эйлера выражается в теореме Эйлера:

алт. текст...

где алт. текст... и алт. текст... взаимно просты.

Функция Эйлера алт. текст... или алт. текст... — это количество чисел от 1 до алт. текст... , взаимно простых с алт. текст....

В частном случае, когда алт. текст... простое, теорема Эйлера превращается в так называемую малую теорему Ферма:

алт. текст...

Подставим под алт. текст... наше число N, и для случайного алт. текст... проверим, что a^(N-1) = 1 (mod N):

Возведем алт. текст... в степень N-1 по модулю N.

Если ответ 1, то N простое, иначе составное.

Для уверенности проделаем всё это 50 раз (возьмём 50 случайных алт. текст...).

И если хоть раз a^(N-1) ≠ 1 (mod N), то N составное.

#3 Бинарное возведение в степень – ссылка - http://e-maxx.ru/algo/binary_pow

Разборы → Meetup Contest #2: Разбор задачи С. Сумма из двух!

 
1
 
1. Отсортируем массив с числами по неубыванию.
2. Для каждого запроса делаем поиск за O(N):
3. Сделаем два указателя L = 1 и R = N
4. Будем двигать L вправо, если a[L] + a[R] < S, и R влево, если a[L] + a[R] > S.
5. Проделываем пока a[L] + a[R] ≠S и L < R.

Асимптотика: O(N) на каждый запрос, O(NM) итого.

Разборы → Meetup Contest #2: Разбор задачи B. Камень-ножницы-бумага

 
0
 

В каждом туре возможно 9 вариантов. 3 из них выигрышные, 3 проигрышные и 3 приводят к ничье или новому туру. Каждый из трех ничейных вариантов вызывают еще 9 вариантов, в которых так же 3 выигрышных, 3 проигрышных и 3 ничейных. Таким образом общее количество возможных игр = 6 + 3 * (6 + 3 * (6 + 3 * … * 9 )) Количество выигрышных игр = 3 + 3^2 + 3^3 + … + 3^n

Вероятность выигрыша начинается с 1/3, если допустим всего один тур и медленно идет к ½ не доходя до этой отметки. В каждой игре вероятность выигрыша равна 1/3, вероятность нового тура 1/3, вероятность нового тура и выигрыша в нем – 1/3*1/3, тогда общая вероятность выигрыша равна 1/3 + 1/3^2 + 1/3^3 + … + 1/3^n

Автор: Ким Вячеслав

Разборы → Meetup Contest #2: Разбор задачи А. Шляпы

 
-1
 

Представим себе, что сидят 3 человека, есть 7 шляп. 3 из них точно черные, поэтому количество белых не превышает 4, то есть M-N. Если все шляпы черные, тогда все очевидно, любой может встать и сказать, что на нем черная. Если одна шляпа белая, а остальные черные, тогда каждый мог подумать таким образом: “Я вижу перед собой две черные шляпы. Если бы на мне была белая, то для других было бы очевидно, что на них черные. Но они так не сказали, когда ведущий спрашивал, следовательно, на мне черная”. Если бы было две белых шляп, тогда можно было бы думать так: “Если бы на мне была белая шляпа, тогда другой увидел бы белую и черную шляпы. Он бы понял, что если бы на нем была белая шляпа, то для третьего ответ очевиден и третий бы в таком случае сразу сказал, что на нем черная. Но третий так не сказал и второй бы мог догадаться, что на нем черная, будь на мне белая шляпа. Но второй так не сделал. Следовательно на мне черная”. Если бы было 3 и более белых шляп, ответ найти было бы не возможно.

Таким образом ответ – последовательность от 0 до минимума из количества возможных белых шляп и количества участников минус один.

for i in 0..min(m-n, n – 1) print i

Автор: Ким Вячеслав

Разборы → Разбор Лабиринт 2

 
0
 

Напишу разбор с более простым решением, чем было предложено в предыдущем разборе.

В задаче есть 4 случая:

  1. Из стартовой вершины в конечную нельзя попасть ни с каким начальным балансом. Т.е. стартовая и конечная вершины находятся в разных компонентах связности. Ответ здесь -1.

  2. В графе отсутствуют циклы с отрицательным весом. Тогда необходимо найти кратчайший из стартовой в конечную, причем нельзя заходить в вершины, если кратчайший путь до нее больше стартового баланса. Если дойти до конечной вершины можем, то ответ баланс - длина кратчайшего пути, иначе ответ -1.

  3. В графе есть циклы с отрицательным весом, но из вершин, принадлежащим данным циклам нельзя достичь конечной вершины. Тогда бесконечное наращивание баланса ни на что не влияет и ответ на задачу аналогичен случаю №2.

  4. В графе есть циклы с отрицательным весом и из вершин, принадлежащим данным циклам можно достичь конечной вершины. Тогда ответ INFINITY.

Будем использовать алгоритм Форда-Беллмана. Этот алгоритм делает n-1 итераций и на каждой итерации перебирает все ребра и улучшает кратчайшие пути. Если в графе нет отрицательных циклов, то кол-во ребер в кратчайшем пути в худшем случае будет n-1. Чтобы определить есть ли отрицательный цикл, проведем дополнительную n-ую итерацию. Если на этой итерации будут продолжаться улучшаться кратчайшие пути, значит вершины до которых этот путь улучшается принадлежат циклам с отрицательным весом.

Тогда задачу можно решить в 2 этапа.

На 1 этапе инвертируем все ребра и запустим тот же Форд-Беллман с конечной вершины. Ограничение на баланс не ставиться. И если путь до какой-то вершины не равен бесконечности, то из этой вершины можно достичь конечную.

Сразу же проверяется и случай №1.

Далее запустим Форд-Беллман из стартовой вершины (с ограничением на стартовый баланс) и сделаем n итераций. На n-ой итерации зафиксируем вершины, до которых кратчайший путь улучшался (это вершины входящие в отрицательный цикл). Если из какой-нибудь из них можно достичь конечной, то ответ INFINITY.

Иначе, если расстояние до конечной вершины равно бесконечности (недостижима), от ответ -1.

Если нет, то ответ баланс - длина кратчайшего пути.

Итоговая асимптотика решения О(n*m)

Разборы → Разбор Цепная дробь 2

 
2
 

Будем решать задачу с помощью сведения ее к аналогичной с меньшими числами. Пусть на i-ом шаге требуется вычислить цепную дробь для p/q. Тогда a[i]=[p/q], p/q=a[i]+1/x, x=q/ p mod q. Таким образом мы свели задачу к решению задачи для дроби x=q/ p mod q. Заметим, что сумма числителя и знаменателя уменьшилась. Так как она будет все время уменьшаться, то рано или поздно получим дробь 1/1.

Разборы → Разбор Склад 1

 
-1
 

Задача на динамическое программирование. Будем хранить состояния типа dp[t][h]. Где t - текущее время, h - текущая высота башни, которую мы построили. а в dp[t][h] мы будем хранить максимальный запас энергии, который имеется у Васи. Если такого состояния не существует dp[t][h]=-1. Изначально dp[0][0]=10. Далее мы будем тратить наш запас энергии, увеличивая время. Т.е. dp[1][0]=9 dp[2][0]=8 и т.д.

Когда Васе сбрасывают торты - у него есть 2 варианта действий. Либо съесть торт, либо увеличить им высоту башни и больше этот торт не трогать. Допустим ему сбросили торт в момент времени T, энергией F и высотой H. Перебираем состояния от dp[T][0] до dp[T][D] (т.е. каждую высоту) Для каждого такого состояния dp[T][j] проделываем следующие действия

1) Находим такое состояние dp[i][j], 0<=i<=T. Чтобы прожив от момента времени i до момента времени T, Вася сохранил максимальный запас энергии и не умер.

maxEnergy=max(MaxEnergy,dp[i][j]-(T-i));

Если maxEnergy!=-1, мы сможем дожить до времени T, имея уже построенную башню высотой j. Тогда выполняем 2 действия:

a) Съедаем торт: dp[T][j]=max(dp[T][j],MaxEnergy+F); И тратим наш запас энергии насколько возможно вплоть до времени 1000. Дальше времени 1000 нам тратить запас энергии бессмысленно, т.к. больше тортов сброшено не будет и улучшить результат мы не сможем.

dp[T+k][j]=max(dp[T+k][j],dp[T][j]-k);

б) Увеличиваем им высоту башни:

dp[T][j+H]=max(dp[T][j+H],dp[T][j]);

И аналогично случаю a - тратим наш запас энергии.

Теперь последний нюанс. Чтобы многократно не улучшать наши результаты одним тортом и исключить проблемы с тортами, сброшенными в один промежуток времени - осуществлять шаг 1 нужно по старым состояниям, назовем их примеру dp2. В конце каждого сброшенного торта будем копировать новое состояние в старое dp2[i][j]=dp[i][j].

В конце просто перебираем состояния от 0 до T, и если dp[Ti][D]!=-1, то ответ - Ti.

Временная оценка - O(Tmax G D), что примерно 10^7 и это укладывается во временные рамки.

Если же построить башню высотой D невозможно, то вычисляем тривиальным алгоритмом максимальное время жизни, съедая на каждом шагу сброшенный торт.

Разборы → Разбор Счастливый билетик - 2 1

 
0
 

Эту задачу можно решить при помощи RSQ (решение "втупую" может и не пройти). Просто строим бинарное дерево за O(N), затем пускаем цикл с 1 до N, и находим максимальную сумму (за O(NlogN)) на отрезке (1-i,i-N). В итоге эффективность нашего алгоритма будет примерно O(NlogN + N) = O(NlogN). ))

Вот самый простой способ нахождения суммы на отрезке за O(logN):


int rsq(int l, int r)
  {
    int ans=0,x,y; 
    x=l+n-1; y=r+n-1;

while(x<y)
{
if(x&1)  ans+=a[x], x++; 
if(!(y&1)) ans+=a[y], y--;

x/=2; y/=2;
}
if(x<y) ans+=a[x]+a[y];
else if(x==y) ans+=a[x];

return ans;

}

rsq

Разборы → Разбор Степень 3

 
1
 

В случае если если b четное тогда выполняем _(2 * a) * ( b / 2) _
если b не четное уменшаем b на еденицу и прибавляем к ответу само число a естественно взяв все по модулю c ,и после этого число b сново четное
а если b == 0 то тогда уже все)
тут скорее всего легче привести код :


typedef unsigned long long int64;

int64 mulmod(int64 a,int64 b,int64 c){                     
    int64 res=0; a %= c;                    
    while(b){                
        if(b & 1) res=(res + a) % c, b--;                  
        else    a=(a * 2) %  c,b/=2;          
    }     
    return (res%c);        
}       

Разборы → Разбор Flags 2

 
1
 

А еще есть более простое решение: будет испольховать одномерную динамику ,как в числах Фиббоначи сначала найдем базу для динамики для N=1 ответ равен 2 (БЕЛЫЙ или КРАСНЫЙ) для N=2 ответ равен так же 2 (БЕЛЫЙ и КРАСНЫЙ ,КРАСНЫЙ и БЕЛЫЙ ,а СИНИЙ мог бы присоеденится лишь между ними) D[1]=2; D[2]=2; для i>2 D[i]=D[i-1]+D[i-2];
память за O(N) и время за O(N)

Разборы → Разбор Бизнес центр 1

 
2
 

если мы нажмем _t_ раз вверх , тогда (n - t) раз должны нажать вниз.
И мы в конце окажемся на этаже t * u - ( n - t) * d.
т.е у нас теперь есть функция f(t)=t * u - ( n - t ) * d;

и можно доказать что функция монотонная.

Prove:
f(t)= t * u - d * n + t * d => f(t)= t * ( u + d ) - d * n так как u>0&d>0 , функция будет строго возрастать. Нам надо найти минимальный _t_ , что бы функция строго была больше нуля. Так как функция монотонная можно применить бинарный поиск

upd: можно еще легче , т.е честно решить уравнение

t * u - d * n + t * d > 0
t * (u+d) > d * n
t > d * n / (u+d)

Здесь понятно что, t = d * n/(u+d)+1

Разборы → Разбор Лесенки 1

 
1
 

Переформулируем нашу задачу на язык математики. В каждом следующем слое (считая сверху вниз) кубиков больше, чем в предыдущем, а в сумме их n. Значит, нам требуется представить n в виде суммы возрастающих натуральных слагаемых.

---

1 | |
---------
4 | | | | |
-----------
5 | | | | | |
-----------------
8 | | | | | | | | |
-----------------

n=1+4+5+8

Пусть в качестве первого слагаемого мы взяли L, тогда нам требуется n-L разбить на слагаемые. Но теперь добавляется дополнительное условие - слагаемые должны быть больше либо равны L+1. Значит, нам достаточно научиться считать число разбиений числа n на слагаемые не меньшие k (обозначим an,k). Есть два случая: слагаемое k либо входит в разбиение (таких способов a[n-k][k+1]), либо нет (таких способов a[n][k+1]). Так как никакое разбиение не подходит одновременно под оба эти случая, то a[n][k]=a[n-k][k+1]+a[n][k+1] Заметим, что для единицы существует единственное разбиение: 1 = 1. Значит a[1][0] = a[1][1] = 1, a[1][f] = 0, где f >= 2. a[n][k] удобно вычислять в порядке невозрастания k. При равных k - в произвольном порядке.

Данный алгоритм выполняет порядка N^2 действий.

источник: olympiads.ru

Разборы → Разбор Подпоследовательности 1

 
-1
 

Пусть c1,c2, ... ,cn, - данная последовательность.

Покажем, как найти длину максимальной возрастающей

подпоследовательности, заканчивающуюся в элементе ck (обозначим ak).

Предположим, она уже найдена.

Удалим из нее последний элемент. Полученная подпоследовательность

является максимальной возрастающей подпоследовательностью,

оканчивающейся в некотором элементе cj (j < k).

Значит, либо ak = max{j < k, cj < ck}{aj} + 1, либо ak = 1, если

таких j не существует. Ответом на поставленную задачу будет максимум

из всех ak.

Число действий, выполненных данным алгоритмом, пропорционально N^2.

источник: olympiads.ru

Разборы → Разбор Степень 1

 
-1
 

на Jave есть такая функция modPow .
т.е ans=a.modPow(b,c).
а a,b,c типа BigInteger.