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

Автор Gerald, 3 месяца назад, По-русски
В этой задаче, нужно было просто посчитать номер лифта, который подходит для каждого участника, а потом прибавить время поездки на этом лифте к времени прибытия лифта. Рассмотрим отдельно три случая.
  • s = f, ans = t.
  • s < f, нужно найти минимальное неотрицательное k такое, что t ≤ (s - 1) + 2(m - 1)k. ans = s - 1 + 2(m - 1)k + (f - s).
  • s > f, аналогично, нужно найти минимальное неотрицательное k такое, что t ≤ 2(m - 1) - (s - 1) + 2(m - 1)k. ans = 2(m - 1) - (s - 1) + 2(m - 1)k + (s - f).
Находить k, можно любым разумным способом, например пользуясь формулами целочисленного деления.

Предположим, что первый сходил числом x ≤ a, тогда рассмотрим остаток rem = x· 109%mod. Очевидно, что если (mod - rem)%mod ≤ b, то второй игрок сможет выиграть. Таким образом нужно перебрать все актуальные значения x (нам не нужно перебирать больше чем mod значений) и посмотреть может ли выиграть второй игрок. Если есть ход проигрышный для второго, то выиграл первый, иначе второй. Т.к. мы перебираем все актуальные ходы первого, то вывести первый выигрышный ход первого (если такой, конечно, существует) не составляет никакого труда.

Утверждение. Если в графе турнире есть хотя бы один цикл, то есть и цикл длины три.

Проведем конструктивное доказательство. Найдем любой цикл в турнире каким-нибудь стандартным алгоритмом, например поиском в глубину. Если цикл не нашелся ответ -1, иначе выберем любые три последовательные вершины цикла v1 v2 v3 (Av1, v2 = Av2, v3 = 1). Так как данный граф является турниром, то либо есть ребро (v3, v1), либо есть ребро (v1, v3). В первом из этих двух случаев, мы сразу находим цикл длины три из вершин v1 v2 v3, во втором мы можем сократить длину уже найденного цикла на одну вершину (просто выкинув вершину v2). 

Будем сокращать длину найденного цикла до тех пор пока не найдем цикл длины три.

Эту задачу можно было решать многими разными методами. Я расскажу решение, которое быстро пишется и быстро работает. Представим дерево рекурсии нашего преобразования F. Это дерево бинарное. Напишем на ребрах, ведущих в левое поддерево, нолик, а на ребрах, ведущих в правое, единичку. Теперь рассмотрим путь некоторого числа a (здесь и далее, будем считать, что мы вычли из всех чисел в массиве, над которым делаем преобразование, единичку). Путь начинается в корне и заканчивается в некотором листе, при этом цифры записанные на ребрах пути в точности произносят битовую запись числа a в порядке от младшего бита к старшему. 

Будем решать задачу рекурсивной функцией по дереву, наподобие того как мы выполняем запрос к дереву отрезков. Вот прототип этой функции.

solve(idx, tl, tr, l, r, u, v)

Функция возвращает ответ, для запроса (l, r, u, v), если рассматриваем только поддерево с позициями [tl, tr], при этом на пути от корня до этого поддерева написано число idx. Внутри функции, если l ≤ tl ≤ tr ≤ r, то ответ считается по формуле, иначе делим отрезок и суммируем результат от левой и правой части.

Как было написано выше, ответ для целого поддерева считается по формуле. Здесь нужно воспользоваться тем, что все числа в поддереве имеют вид k· 2depth + idx, где depth глубина поддерева. Нужно найти такие k, что u ≤ k· 2depth + idx ≤ v и потом просуммировать соответствующие им числа.   

Асимптотика этого решения O(m· log(n)· (ответдляподдерева)). Ответ для поддерева можно считать за O(logn) можно за O(1).

В данной задаче предполагалось решение с использованием heavy light декомпозиции. Граф, заданный в условии, представляет собой цикл, на который подвешены деревья. Для каждого дерева заведем структуру (heavy light + дерево отрезков), которая будет уметь делать change на пути от вершины к какому нибудь её предку, а также поддерживать сумму единичек. Такую же структуру заведем для цикла.  

Предположим, что цикла вообще нет, т.е. есть просто набор деревьев. Тогда общее количество ребер однозначно определяет количество компонент связности (Каждое включенное ребро делает на одну компоненту меньше). 

Предположим, что есть только цикл. Тогда, по аналогии, общее количество включенных ребер однозначно определяет количество компонент связности. 

Будем поддерживать количество включенных ребер в цикле и во всех поддеревьях. Тогда ответ на задачу это Compscicle + Compstrees - CntCicle, где Compscicle - количество компонент в цикле, Compstrees - количество компонент суммарно во всех деревьях, CntCicle - количество вершин в цикле.

Осталось только описать структуру для выполнения запросов и поддержания количества включенных ребер. Я ограничусь только ссылкой на соответствующий ресурс emaxx.ru.

 
 
 
 

 
2 месяца назад, #
Правка 2   Проголосовать: нравится +2 Проголосовать: не нравится

Are you just translate your editorial (Russian version) into English Version by Google Translate?

All right, I saw your tags anyway :)

 
2 месяца назад, #
  Проголосовать: нравится +2 Проголосовать: не нравится
Я решал задачу А на С, и мне потребовался массив int размером 100000. Он не помещался в памяти. Так и было задумано?
  •  
    2 месяца назад, # ^
      Проголосовать: нравится 0 Проголосовать: не нравится
    Такой массив занимает в памяти не больше мегабайта(на деле  ≈ 400кб), а ограничения в задаче  —  256 МБ.
    Может быть, покажете код?
  •  
    2 месяца назад, # ^
      Проголосовать: нравится +3 Проголосовать: не нравится
    100000 элементов размера 4 байта (int же), т.е. 400000 байт. На калькуляторе делим 400000 на 1024 и получаем 390,625 килобайт. Не поместится только если вы пишете на Turbo Pascal.
 
2 месяца назад, #
  Проголосовать: нравится -2 Проголосовать: не нравится
Вот код
#include <stdio.h>
#include <conio.h>
int main()
{
    FILE* fin;
    fin=fopen("f.in", "r");
    int n, m;
    fscanf(fin, "%d%d", &n, &m);
    int mas1[100000];
    int mas2[100000];
    int mas3[100000];
    for(int i=0; i<n; i++)
        fscanf(fin, "%d%d%d", &mas1[i], &mas2[i], &mas3[i]);
    for(int i=0; i<n; i++)
    {
        if(mas1[i]==mas2[i]){
            printf("0\n");
            continue;
        }
        int k = mas3[i]/(m-1);
        int l = mas3[i]%(m-1);
        int r;
        if((mas1[i]<mas2[i] && l>mas1[i]-1 && k%2==0) ||
          (mas1[i]>mas2[i] && l>m-mas1[i] && k%2==1))
            k+=2;
        if((mas1[i]>mas2[i] && k%2==0) ||
          (mas1[i]<mas2[i] && k%2==1))
            k++;
        if(k%2==0) printf("%d\n", k*(m-1)+(mas2[i]-1));
        else printf("%d\n", k*(m-1)+(m-mas2[i]));
    }
    //printf("%d %d", n, m);
    fclose(fin);
    getch();
    return 0;
}
если с ожиданием.
  •  
    2 месяца назад, # ^
      Проголосовать: нравится 0 Проголосовать: не нравится
    Надо вынести массивы из main наверх, в стеке не хватит памяти.
 
2 месяца назад, #
  Проголосовать: нравится 0 Проголосовать: не нравится
Please tell me, In problem B

rem = x· 109%mod

why 
109 is used?? why its particularly 109?
 
5 недель назад, #
  Проголосовать: нравится +30 Проголосовать: не нравится
Another way to do problem E is to use link-cut trees, which I invented.  (They're described in this paper: http://www.cs.cmu.edu/~sleator/papers/self-adjusting.pdf )  My code for this problem using link-cut trees is here: http://www.codeforces.com/contest/117/submission/842663  The link-cut trees are in the Node class, near the end of the file.

Not that it matters here, but link-cut trees give you a running time of O(n log n) instead of the O(n log^2 n) solution described here.  I also think they're rather elegant, if I do say so my self.

                   ---Danny Sleator
  •  
    5 недель назад, # ^
      Проголосовать: нравится +6 Проголосовать: не нравится
    Oh, glad to see you here, it's really perfect solution. I've heard a lot about your trees, and about a lot of magical things they can do, but never tried to use them in practice.

    I think, I should try to solve this problem in this way, the truth, when I first tried to read this article, I found it quite difficult, I hope I will be able to overpower her at this time.

    With great respect
    Gerald Agapov
    •  
      5 недель назад, # ^
        Проголосовать: нравится +8 Проголосовать: не нравится
      I've submitted a new version of my solution, this time with a better description of how it works.  http://www.codeforces.com/contest/117/submission/860934

      This, combined with looking at the code, should make it a lot easier to understand.

      ---Danny
  •  
    5 недель назад, # ^
      Проголосовать: нравится +20 Проголосовать: не нравится

    A legend in this thread!

 
45 часов назад, #
  Проголосовать: нравится 0 Проголосовать: не нравится
Can anyone please explain the idea behind niyaznigmatul's solution to problem C? (http://codeforces.com/contest/117/submission/715444)

I think it boils down to proving this fact:

If there's an edge from to and out[j] >= out[i] then certainly there's a cycle i -> j -> k -> i for some node k (where out[u] is the number of outgoing edges from node u).

Any idea on how to prove this? I can't convince myself that his solution is correct.