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

Автор AlexSkidanov, 14 лет назад, По-русски

Я расскажу как я решал задачи, которые я сдал.
Мне, в свою очередь, интересно, как решать B :о)

Очень клевый контест для командной работы -- в задачах надо много думать и не очень много кодить. Но все равно поверить, что кто-то на ней сдал девять задач невероятно :о

Результаты с тимуса: http://acm.timus.ru/monitor.aspx?id=83

Результаты с петрозаводска: http://karelia.snarknews.info/index.cgi?data=macros/run&menu=index&head=index&round=01&sbname=2010s&class=2010s

 

Задача C.
Можно заметить, что окружность вписывается тогда и только тогда, когда произведение радиусов окружностей, между которыми мы ее вставляем, является квадратом рационального числа. Более того, если их радиусы равны A/(B^2) и A/(C^2), то радиус впихнутой окружности будет A/((B+C)^2). То есть если с самого начала можно впихнуть окружность, то можно будет и на каждой следующей итерации, и наоборот. Отсюда, сначала проверим, является ли произведение данных нам радиусов квадратом рационального числа, и, если да, представим радиусы в виде
r1 = (a) / (b)
r2 = (a) / (c)
Где a = r1*r2/gcd(r1,r2). После этого будем на каждой итерации вычислять радиус центрального шарика, и смотреть, с какой стороны относительно центрального шарика нужный нам - и продолжать рекурсивно.
Отдельно надо рассмотреть крайний случай, когда впихнуть шарик нельзя, но запрашивается один из крайних.

Задача G.
Решим по очереди для каждого делителя N, и в конце для N, так, чтобы к моменту, когда мы решаем для некоторого делителя, для всех меньших делителей мы уже знали ответ.
Теперь, чтобы решить для N перебираем все делители N, для каждого делителя смотрим, каков шанс нарваться на этот делитель в интервале [1,10^18], причем так, чтобы при этом не делилось ни на какой больший делитель. Это делается с помощью включения-исключения. Допустим, что мы решаем для числа 12, и хотим узнать, каков шанс нарваться на число, кратное двум, но не кратное четырем или шести. Ответ будет
chance = ( 10^18 / 2 - 10^18 / 4 - 10^18 / 6 + 10^18 / 12 ) / 10^18
Для каждого делителя A прибавляем к ответу ( ans[A] + ans[N / A] ) * chance.
В конце в ответе надо учесть, что, прежде, чем попасть в любой такой делитель, мы сколько-то раз потыкаемся в взаимнопростые числа. Это учитывается как-то так:
ret = ( ret + 1 ) / (allChances);
Где allChances - это сумма всех chance для всех делителей N.

Задача I.
Надо найти N такое, что следующая формула вернет ноль:
- a[n - 1] + (n-1)/n * (- a[n - 2] + (n-1)/n * (- a[n - 3] + (n-1)/n * (...) % n) % n) % n
Восстанавливать надо с конца, получается
ret = 0;
ret += a[n - 1];
ret %= n;
ret *= n
ret /= (n-1)
ret += a[n - 2];
ret %= n^2;
ret *= n;
ret /= (n-1)
...
То есть, тоже самое псевдокодом
for(i from N-1 to 0) {
 ret = (ret + a[i]) % mod;
 if( i == 0 ) break;
 ret *= N;
 mod *= N;
 ret /= (N-1);
}
Тут самое сложное - это сделать это все быстро. Особенно деление по непростому модулю. Так как это длинная арифметика, и решать надо все равно на Java, кажется очевидным попользовать модный modInverse, но такое решение ловит TLE. Я в конце концов пропихнул такое решение:
for(i from N-1 to 0) {
 ret = (ret + a[i] * mul) % (mod_mul);
 if( i == 0 ) break;
 ret *= N;
 mod *= N;
 mul *= (N-1);
 mod_mul *= N*(N-1)
}
ret = ret * mul.modInverse(mod_mul) % mod;


Задача H вроде тривиальная - ДП по подмножествам.
В задаче D строим для первых 100 элементов, и мучительно угадываем закономерность.

  • Проголосовать: нравится
  • +35
  • Проголосовать: не нравится

14 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится
В Б прошло такое: храним списки смежности, матрицу смежности сжатую в 30 раз.

 Перебираем пару вершин (u, v), каких операторов мы выбираем, делаем первую проверку, что сумма степеней u и v больше либо равна n.

Вторая проверка делается за n/30 битовых операций -- проверка, что все вершины достижимы из выбранных.

Третий оптимайз в том, чтобы сделать break когда максимальный вес ребра для текущей пары станет больше глобального результата. такое проходит на грани TL.

P.S. мы поверили в такое решение из-за того, что ребер в графе не так уж и много.
  • 14 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    В B заметим факт, что для того чтобы покрасить все вершины правой доли надо взять хотя бы одну вершину левой доли из двух степень которой >= n / 2. А таких вершин мало) потом решаем в лоб
  • 14 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится
    Вот на твоем аватаре - я правильно понимаю, что компьютер перед тобой заблокирован, но ты что-то на нем делаешь. Причем положение рук четко свидетельствуют о том, что ты играешь в этот момент в Quake :о
    • 14 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      0 % попадания=) комп не заблокирован, а играю в варкрафт иногда.
      • 14 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится

        "играешь в квак" имелось ввиду в этот конкретный момент а не вообще :о)

        как он не заблокирован, если на мониторе заставка какая-то :о)

        • 14 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          это картинка на рабочем столе, все окна свернуты
        • 14 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          Достаточно зайти к нему в профиль, чтобы посмотреть на экран крупным планом.
14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Unable to parse markup [type=CF_HTML]

14 лет назад, # |
  Проголосовать: нравится +3 Проголосовать: не нравится
можно поподробнее про задачу H?
  • 14 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    И, объясните, пожалуйста, как получается в ответе на тест из условия третья строчка?
    • 14 лет назад, # ^ |
      Rev. 3   Проголосовать: нравится +3 Проголосовать: не нравится
      дело в том что варианты расположения детей до того как придет еще один ребенок не равновероятны.
  • 14 лет назад, # ^ |
    Rev. 3   Проголосовать: нравится 0 Проголосовать: не нравится
    Сначала посчитаем такую динамику dm[mask] - это вероятность того, что на карусели дети займут множество mask.
    База dm[0] = 1
    Пересчитывается так: пусть известно dm[mask] , сейчас приходит ребенок и становится к позиции cur, ищем первую незанятую позицию в маске -- pos, т.е. рассматриваем позиции cur % n, ( cur + 1) % n, (cur + 2) % n и т.д. сейчас нужно сделать так:
     dm[mask | (1 << pos)] += dm[i] * 1 / n; 

    Сейчас посчитаем матожидание, зафиксируем некоторую mask, и начальную позицию cur, опять же найдем первую свободную позицию и сделаем так:
    ans[len] += dm[mask] * 1 / n * t , где len - кол-во человек на карусели(кол-во единиц в mask), t - сколько секунд нужно ждать для незанятой позиции, ans[i] - матожидание времени если на карусели было i детей.
14 лет назад, # |
Rev. 6   Проголосовать: нравится +3 Проголосовать: не нравится
B можно решать за так:
Пусть у нас есть две вершины u и v, тогда мы можем найти стоимость покрытия этими двумя вершинами за O(deg(v)) исполузься сжатую матрицу смежности и списки смежности.
Теперь пусть тогда переберем все пары вершины u и v такие что , и заметим, что таких вершин u не больше . Каждая пара у нас обрабатывается за O(deg(v)), поэтому суммарная стоимость будет . Другие пары проверять (пару у которых степень обоих вершин меньше ) нет смысла т.к. они точно не покроуют все множество вершин. Остался случай когда он решается влоб.
  • 14 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится
    На самом деле можно решать за O(m2 / n) если в качестве вершин u брать вершины степени > n / 2
  • 14 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    И даже сжатую матрицу смежности не обязательно хранить если мержить отосрченные списки смежности. Появится прибаква - сумма по u степеней u, которая <= число таких u * n.
14 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

Для решения D использовал следующее: http://ru.wikipedia.org/wiki/Линейный_конгруэнтный_метод

Из текста ссылки следует такое решение:

1) Находим все простые делители числа m, перемножаем их -> prod

2) Если (m - 1) % 4 == 0 -> умножаем полученное произведение на 2 -> prod *= 2

утверждается, что a может быть только 1, prod, prod * 2, ..., a < m

Отсюда уже следует ответ

14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Задача C.  Здесь не обезательно юзать числа 10^18 для того что бы посчитать окончательный ответ - здесь можна предположить что случайное число имеем  пределы от 1 до n, что значительно упрощает задачу )
14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Как на счет задачи F, 2 тернарных поиска дали ТЛ
  • 14 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    всмысле вложенных?
    • 14 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Тернарный поиск по двум аргументам, сначала по x внутри него по y
      • 14 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        Решение с тернарным поиском мало того, что очень медленное, так еще и нестабильное (мое иногда сильно промахивается от оптимума). Задача сводится к одному бинпоиску. Он в таймлимит укладывается.
14 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Если еще актуально - мои идеи по контесту.

Задача B (которую так хотел Alex) - это тупой брутфорс. Предлагаю подумать и доказать, почему он тут с лихвой заходит в таймлимит.

Задача F - хорошее сочетание математики и кодинга. С точки зрения математики - надо найти FOCи для точки оптимума и из них найти оптимальные углы между лучами, соединяющими точку оптимума с тремя городами. Затем написать код, который "натягивает" эту лучистую структуру на фактически данные вам точки (это можно сделать одним бинпоиском).

Еще я свел задачу E к красивому возведению матрицы [(int)sqrt(n) n, 1 (int)sqrt(n)] в k-ю степень, однако проблема в том, что дробь, которая получается в итоге перемножением этой матрицы, может быть сократимая, и на что ее сокращать - неясно. Кто знает, как разрешить эту проблему (или как по-другому решить эту задачу) - буду благодарен за разбор.
  • 14 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится
    В E есть две части решения разложить корень из D в цепную дробь, а потом увидить (или знать формулы перехода от дроби [a0;a_1,...a_k] -> [a0;a1,...,a_k,a_{k+1}] в виде умножения столбца на матрицу... так как наше разложение циклится то нам все лишь надо возвести матрицу перехода для всего периода в нужную степень, и подомножать на неполный период. Всё. дробь получается автоматически не сократимой
»
5 лет назад, # |
Rev. 2   Проголосовать: нравится -8 Проголосовать: не нравится

О думал как можно без длинки обойтись в задаче С и понял ваш метод. Метод просто супер