Блог пользователя witua

Автор witua, 13 лет назад, По-русски
DIV2-A Lucky Ticket:

В этой задаче все очевидно: если все цифры счастливы и сумма первых n / 2 равна сумме последних n / 2, то ответ YES, иначе - NO. Все это можно сделать одним проходом циклом по номеру и одной проверкой.

DIV2-B Lucky Mask:

Можно увидеть, что ответ на задачу не будет превосходить никогда 1777777. Поэтому, все что нужно сделать это написать какую-то функцию F(x), которая бы возвращала маску числа x. После этого нужно просто написать такой код:

x = a + 1;

while (F(x) не равно b)

увеличить x на 1;

После этого в x будет содержаться результат.

DIV2-C DIV1-A Lucky Transformation:

Найдем два числа: c47 (количество таких позиций i строки, что ai = 4, bi = 7), c74 (количество таких позиций i строки, что ai = 7, bi = 4). Результатом после этого будет, очевидно, число max(c47, c74) (так как min(c47, c74) операций пойдут на обмен цифр, а остальные - на переключения цифр).

DIV2-D DIV1-B Lucky Number 2:

Пусть у нас есть какой-то результат в виде строки s. Давайте удалим из нее все повторы, то есть пока есть два одинаковые символы рядом, один из них удалим. На F(47) и F(74) такое, очевидно, не повлияет. Тогда в такой строке 4 и 7 будут чередоваться. При этом видно, что |F(47)-F(74)| ≤ 1. Поэтому, если |a3 - a4| > 1, то результату не существует. Иначе нам нужно перебрать возможные "корни" (строчки после выполнения выше упомянутой операции удаления одинаковых цифр) результата, по которым нужно построить результат. Если a3 = a4, то корней возможных есть два: строчка вида 474747474...474 или 74747474...747 (подогнана по размеру под a3). Если a3 < a4, то корнем будет строчка вида 747474...7474, иначе, если a3 > a4, то корень - 47474747...4747. При этому количество блоков 47 и 74 нужно делать ровным a3 и a4, соответственно.

Теперь нужно по корню построить результат. Но перед тем нужно проверить, не превышает ли количество 4 в корне a1, а количество 7 - a2. Если так, то результата не существует. Иначе нам нужно доставить какое-то количество 4 и 7, которых не хватает корню. Очевидно, что для сбережения лексикографической минимальности, все 4 нужно доставить рядом с первым вхождением цифры 4 в корень, а 7 - рядом с последним вхождением 7. На a3 и a4 это, конечно, не повлияет.

DIV2-E DIV1-C Lucky Different: 

Как всем, наверное, известно, счастливых чисел на промежутке [1;109] есть 1022. Воспользуемся этим фактом для решения задачи. Пусть C[i] - сколько раз i-е счастливое число встречается в массиве a. Теперь заведем ДП (динамическое программирование) с параметрами DP[pos][cnt] - сколько существует подмножеств из всех счастливых цифр массива таких, что в них использованы только счастливые до pos-го, а размер подмножества ровен cnt. DP[0][0], очевидно, ровно 1. Если мы в каком-то стане DP[pos][cnt], то можно не взять pos-е счастливое число вообще. То есть DP[pos+1][cnt] += DP[pos][cnt]. Если же мы возьмем pos-е счастливое число, то сделать это можно С[pos] способами, то есть DP[pos+1][cnt+1] += DP[pos][cnt]*C[pos].

Теперь нужно найти полный результат. Для этого переберем количество счастливых чисел в подмножестве, пусть это i. Тогда это число нужно еще домножить на C(countunlucky, k - i) (биноминальный коэффициент), где countunlucky - количество не счастливых чисел массива. Суммой по всем таким i и будет результат.

Также в этой задаче нужно не забывать все аккуратно брать по простому модулю 109 + 7, а для вычисления бин. коэффициентов нужно использовать обратный элемент в кольце по модулю.

DIV1-D Lucky Pair:

В основе решения стоит тот факт, что количество счастливых чисел до 1000. Давайте решим такую задачу: у нас есть массив из 1000 элементов, каждый до 1000. Нужно найти количество таких пар промежутков, что-бы у них не было одинакового числа. Для этого давайте зафиксируем i - левую границу правого промежутка. Теперь будет перебирать j от i до n - 1 и поддерживать множество чисел из промежутка [i;j]. Очевидно, что время-от-времени в это множество (пусть это будет S) будут добавляться числа, при этом каждое новое ровно один раз. Тогда если у нас в множество додается какое-то число, нам нужно посмотреть на все вхождения этого числа на промежутке [0;i - 1]. Если есть такое вхождение k (k < i), то не может быт такого левого хорошего промежутка (для правого [i;j]) [l;r], что l ≤ k и k ≤ r. По этому мы можем использовать set и каждое из приходящих вхождений закидывать в set, поддерживая количество хороших левых промежутков (таких что в этом промежутке нет ни одного числа из set), для этого пригодиться функция S.lowerbound сета. 

А теперь у нас между этими числами есть еще и числа, на которые смотреть вообще не нужно (у нас это несчастливые числа). Если фиксировать только такие i что a[i] счастливое и перебирая j (j > i) только такие, что a[j] - счастливые то нам можно за O(n2 * logn) найти таким методом количество таких пар, что правый промежуток содержит хотя бы одно счастливое число. Теперь еще нужно количество таких пар, что правый промежуток не содержит счастливых. Для этого переберем i - левую границу правого промежутка, a[i] - не счастливое. Пусть f(i) - минимальное j, (j > i) и a[j] - счастливое. Тогда у нас есть f(i) - i способов поставить правую границу правого промежутка (так что-бы не содержал счастливого). А левый промежуток может быть любим - способов это сделать есть i * (i + 1) / 2 (нумерация с 0).

DIV1-E Lucky Queries:

Давайте решим задачу деревом отрезков. Будем держать такие числа в каждой вершине дерева:

n4 - количество цифр 4 на промежутке.
n7 - количество цифр 7 на промежутке (на самом деле n7 = length - n4, то для наглядности будем использовать и n7).
n47 - размер максимальной неубывающей подпоследовательности на промежутке.
n74 - размер максимальной невозрастающей подпоследовательности на промежутке.

Тогда когда мы делаем "switch", то для нужных вершин делаем просто swap(n7, n4), swap(n47, n74). Для каждой вершины дерева мы должны поддерживать эти числа: n4(father) = n4(left_son) + n4(right_son), n47 = max(n47(left_son) + n7(right_son), n4(left_son) + n47(right_son), n4(left_son) + n7(right_son)). Результатом для запросов count тогда будет n47 корня дерева.

Для большей информации о дереве отрезков читайте прекрасную статью от paladin8.
Разбор задач Codeforces Round 104 (Div. 1)
Разбор задач Codeforces Round 104 (Div. 2)
  • Проголосовать: нравится
  • +76
  • Проголосовать: не нравится

»
13 лет назад, # |
  Проголосовать: нравится +2 Проголосовать: не нравится
А где можно прочитать про "вычисление биномиальных коэффициентов с использованием обратного элемента в кольце по модулю"?
  • »
    »
    13 лет назад, # ^ |
      Проголосовать: нравится +3 Проголосовать: не нравится
    С(n,k) = n! * inv(k!) * inv((n-k)!)
    inv(x) = pow(x, mod-2)
    • »
      »
      »
      13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Или ещё можно побыстрее, напрекалчить C[i] = C[i-1]*inv(i)*(n-i+1)
  • »
    »
    13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Здесь про обратный элемент. Ну и использовать известную формулу числа сочетаний.
»
13 лет назад, # |
  Проголосовать: нравится -17 Проголосовать: не нравится
Смешно читать ломаный русский :)
"то есть пока есть два одинаковые символы рядом,
"то результату не существует"
  • »
    »
    13 лет назад, # ^ |
      Проголосовать: нравится +2 Проголосовать: не нравится
    Спокойно, разбор еще под редактированием ;)
  • »
    »
    13 лет назад, # ^ |
      Проголосовать: нравится +9 Проголосовать: не нравится
    Предлагаю команде сайта, при необходимости (русский -- не родной для автора) помогать не только с английской версией, а и с русской. С одной стороны -- таки есть ошибки, затрудняющие чтение, с другой -- очень даже видно, что все ошибки не от неграмотности, а исключительно от смешения языков.

    Впрочем -- возможно, на наиболее критичных фрагментах это и делается (в самих условиях задач таких ошибок, кажется, не было, а разборы можно и потом исправить).
»
13 лет назад, # |
  Проголосовать: нравится +3 Проголосовать: не нравится
div2-С, ну почему ты С.
Сообразить, какой вид имеет решение этой задачи, мне кажется, требовало меньше времени, чем даже закодить B.
  • »
    »
    13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    А мне кажется, что С на своем месте. В ней надо было хотя бы немного подумать, а в задаче B тупо написать.
»
13 лет назад, # |
  Проголосовать: нравится +17 Проголосовать: не нравится
DIV1-B Lucky Number 2:
in case that a3 = a4, another root that we must be consider is 747474...7. 
because in case of 1 2 1 1, 474 root cannot fulfill the string but 747 does.
»
13 лет назад, # |
Rev. 2   Проголосовать: нравится -15 Проголосовать: не нравится
Можно ли выражение 
DP[pos+1][cnt] += DP[pos][cnt];
заменить на 
DP[pos+1][cnt] = DP[pos][cnt]?

И то же самое сделать с DP[pos+1][cnt+1] += DP[pos][cnt]*C[pos]?

Спрашиваю, потому как непонятно, зачем понадобилась здесь аккуммуляция значений в состоянии
  • »
    »
    13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Если я правильно понял, то после того как Вы запустите дп, у Вас у всех станах будет либо 0, либо 1, а это явно плохо.
    • »
      »
      »
      13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Блин, всё равно не ясно :-(
      • »
        »
        »
        »
        13 лет назад, # ^ |
          Проголосовать: нравится +1 Проголосовать: не нравится
        Ну суть этого всей штуки (динамического программирования) в том, что-бы быстро посчитать что-то, что можно охарактеризовать станами. В данном случаи станов два - номер счастливого числа и количество счастливых. 

        Если вы не будете делать, как вы говорите, аккумуляции, то в результате ничего не получите, ведь нужно использовать уже подсчитанные результаты, и как-то их объединять, в данном случаи - суммировать, а простое присвоение не будет ничего менять. Вам ведь нужно количество способов.
        • »
          »
          »
          »
          »
          13 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          Спасибо за комментарий.
          Идея динамического программирования мне понятна, только вот не всегда удаётся её использовать в каком-то конкретном случае, вот например, в этом.
          У меня ещё один вопрос. Когда считаем массив DP, мы также собираем и те последовательности, в которых могут быть одинаковые счастливые числа. Я не совсем понял, как исключить те последовательности, в которых встречаются одинаковые счастливые числа.
          • »
            »
            »
            »
            »
            »
            13 лет назад, # ^ |
              Проголосовать: нравится +1 Проголосовать: не нравится
            На самом деле мы не считаем подпоследовательностей с одинаковыми счастливыми числами. Ведь когда мы делаем DP[pos+1][cnt] += DP[pos][cnt], то не используем pos-e счастливое число, и далее мы его тоже не будем использовать, так как pos увеличилось и мы будем рассматривать другие счастливые числа. 

            А когда мы делаем DP[pos+1][cnt+1] += C[pos]*DP[pos][cnt], то выбираем pos-е счастливое число (одно из C[pos] что есть в массиве a) и опять увеличиваем pos, поэтому такие самые счастливые у нас не войдут в подпоследовательность.

            Учтите, что pos - не позиция во входном массиве, а позиция в списке всех 1022 счастливых чисел, а C[i] - сколько раз pos-e счастливое число входило в массив a.
            • »
              »
              »
              »
              »
              »
              »
              13 лет назад, # ^ |
                Проголосовать: нравится 0 Проголосовать: не нравится
              Спасибо, отличное объяснение! Тот факт, что pos - это позиция в списке всех 1022 счастливых чисел существенно прояснило ситуацию. Так что изначальный вопрос в ветке разрешился сам собой.
»
13 лет назад, # |
Rev. 6   Проголосовать: нравится 0 Проголосовать: не нравится
Объясните почему срабатывает assert?
for(int i = 0; i < 1024; i++)
for(int j = 0; j < 1024; j++)
d[i][j] = 0;
for(int i = 0; i < 1024; i++)
d[i][0] = 1;
for(int i = 1; i <= sz(v); i++)
for(int j = 1; j <= i; j++)
d[i][j] = (d[i - 1][j] + ((d[i - 1][j - 1] * v[i - 1]) % MOD)) % MOD;
for(int i = 0; i <= sz(v); i++)
for(int j = i + 1; j < 1024; j++)
assert(d[i][j] == 0);

  • »
    »
    13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    массив маловат?
    • »
      »
      »
      13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      это задача C, там всего максимум может быть 1022 счастливых чисел.
      • »
        »
        »
        »
        13 лет назад, # ^ |
          Проголосовать: нравится +5 Проголосовать: не нравится
        границы массива у тебя правильные? не 512 на 512? сделай 1050 на 1050. и проверь границы других массивов. похоже на то, что где-то происходит вылет за границу массива, и в эту память пишется что-то другое. В первую очередь проверь массивы что объявлены выше.
        • »
          »
          »
          »
          »
          13 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          разобрался спасибо. Да проблема была в размере массива.
»
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Прошу кого-нибудь помочь, написал задачу Е, посмотрел у других участников, вроде сходиться, но никак не могу найти ошибку, всё время вылетает один и тот же тест!Спасибо.
  • »
    »
    13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Проверка счастливое ли число неправильная - в твоём решении считается, что ДА, если хотя бы  одна 4 или 7 есть в числе
    • »
      »
      »
      13 лет назад, # ^ |
        Проголосовать: нравится +3 Проголосовать: не нравится
      Действительно, вы правы. Большое спасибо!
»
13 лет назад, # |
  Проголосовать: нравится +14 Проголосовать: не нравится
problem E can be solve using segment tree with each node maintain the following information:
n4: number of four in the range
n7: number of seven in the range
f47: maximum non-decreasing sequence length
f74: maximum non-increasing sequence length
mask: reverse mask

when reverse the digits in the node, we just need to swap(n4, n7), swap(f47, f74) 
when update the node, n4(father) = n4(leftson) + n4(rightson), 
f47[father] = max(f47[leftson] + n7[rightson], n4[leftson] + f47[rightson], n4[leftson] + n7[rightson]);

For query, ans is f47 in the root node.

Waiting solution D. 

»
13 лет назад, # |
Rev. 2   Проголосовать: нравится +28 Проголосовать: не нравится

Вот чем мне нравится CodeChef, так тем, что разбор от автора требуют представить ДО начала контеста. И публикуют его сразу по концу контеста, когда всем участникам это крайне интересно. 
А тут уже и другие соревнования прошли, и новые грядут, а всё "Coming soon...".

»
9 лет назад, # |
  Проголосовать: нравится -8 Проголосовать: не нравится

Can someone explain Div 2E/1C solution a little more?

»
5 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

In div1 E last problem can u please check where i am wrong in the code,i have used the same concept but still getting wrong answer solution

  • »
    »
    5 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

    The problem with your code is in lazy update, i.e marked[2*v]=true ..... and so on everytime your setting it to true, so suppose if I give you a query say switch 4 6 and then again switch 4 6 so indices from 4 to 6 will be restored as it was and your marked array should store false as there is no update below this position but you are always setting it to true therefore after two queries of switch type your marked array will hold information that will change your segment tree when it is not needed. But that is the not the only error in your code, These are some additional problems : 1. You also need to check your lazy tree first while updating. 2. You are combining the data incorrectly you also need count of 4s and count of 7s while updating the information regarding increasing sequence. Here is my submission https://codeforces.net/contest/145/submission/59416514 (Ignore the template)

»
5 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

DIV 1 E n74: maximum non-increasing subsequence in range. Why do we need this?

»
5 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

DIV 1 E Can anyone please point out the mistake? Getting WA for test case 2.

My code : #here8461366

Reference code: here

THankyou very much

»
3 года назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Why is 140696075 exceeding the time limit?

»
3 года назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Why is 140696075 exceeding the time limit?