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

Автор Gerald, 13 лет назад, По-русски
В этой задаче, нужно было просто посчитать номер лифта, который подходит для каждого участника, а потом прибавить время поездки на этом лифте к времени прибытия лифта. Рассмотрим отдельно три случая.
  • 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.

Разбор задач Codeforces Beta Round 88
  • Проголосовать: нравится
  • +31
  • Проголосовать: не нравится

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

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

All right, I saw your tags anyway :)

13 лет назад, # |
  Проголосовать: нравится +1 Проголосовать: не нравится
Я решал задачу А на С, и мне потребовался массив int размером 100000. Он не помещался в памяти. Так и было задумано?
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Такой массив занимает в памяти не больше мегабайта(на деле  ≈ 400кб), а ограничения в задаче  —  256 МБ.
    Может быть, покажете код?
  • 13 лет назад, # ^ |
      Проголосовать: нравится +4 Проголосовать: не нравится
    100000 элементов размера 4 байта (int же), т.е. 400000 байт. На калькуляторе делим 400000 на 1024 и получаем 390,625 килобайт. Не поместится только если вы пишете на Turbo Pascal.
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Вот код
#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;
}
если с ожиданием.
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Надо вынести массивы из main наверх, в стеке не хватит памяти.
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Please tell me, In problem B

rem = x· 109%mod

why 
109 is used?? why its particularly 109?
13 лет назад, # |
  Проголосовать: нравится +53 Проголосовать: не нравится
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
  • 13 лет назад, # ^ |
      Проголосовать: нравится +25 Проголосовать: не нравится
    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
    • 13 лет назад, # ^ |
        Проголосовать: нравится +19 Проголосовать: не нравится
      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
      • 10 лет назад, # ^ |
        Rev. 4   Проголосовать: нравится 0 Проголосовать: не нравится

        In the link operation, shouldn't we update the counts? Edit: it's done in expose.

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

        I am probably misunderstanding something, but in link, shouldn't one of q's children be made q? If this isn't the case, then how does one construct a link/cut tree to represent a whole tree (using your implementation)?

  • 13 лет назад, # ^ |
      Проголосовать: нравится +43 Проголосовать: не нравится

    A legend in this thread!

13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Can anyone please explain the idea behind niyaznigmatul's solution to problem C? (http://codeforces.net/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.
»
12 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Another solution for problem C. let us consider the vertex with the biggest outcoming degree. if the degree is equal to n-1 we could ignore it ans solve the problem for remaining graph. otherwise we could name this vertex as a (( King )) of digraph. we know that every vertex could achieve from king with distance at most 2.so because of what we say before there is vertex like V that the edge between king and V is (( V -> king )). and we just need the path from king to V and we could find the middle vertex easily that we name it U. so the answer to the problem is (( king , U , V )).

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

Need help for Div 2 C. Getting the Wrong Answer for test case #34. According to my solution, I do dfs on vertexes and store their levels with respect to vertex 1(level 0). As soon as I add a vertex to stack I check whether the difference between its old level(only if that vertex had been visited before, else its level will be -1 by default) and new level (obtained by 1+current level of the top vertex of the stack)is equal to 3 or not. If it is, then I store current top vertex and the vertex whose difference in levels was 3. Now I only need to find the last vertex such that there is an edge from first to second and second to third and third to first.

My Solution

Can anyone explain why getting wrong answer or give a short test case?????

THANKS