AlexSkidanov's blog

By AlexSkidanov, 14 years ago, In Russian

Я расскажу как я решал задачи, которые я сдал.
Мне, в свою очередь, интересно, как решать 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 элементов, и мучительно угадываем закономерность.

  • Vote: I like it
  • +35
  • Vote: I do not like it

14 years ago, # |
  Vote: I like it 0 Vote: I do not like it
Если еще актуально - мои идеи по контесту.

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

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

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