Часто в задачах требуется посчитать что-то по простому модулю (чаще всего
Обычные арифметические операции выполняются не сильно сложнее — просто нужно брать модули и заботиться о переполнении. Например:
= (a + b) % mod;
c = (mod + a - b) % mod;
c = a * b % mod; c
Но вот с делением возникают проблемы — мы не можем просто взять и поделить. Пример:
Нужно найти некоторый элемент, который будет себя вести как
Если модуль
Теорема.
Доказательство. (для понимания несущественно, можно пропустить)
Здесь
Теперь два раза «поделим» наш результат на
Получается, что
Приведем код, который позволяет считает
int t[maxn]; // факториалы, можно предподситать простым циклом
// бинарное возведение в степень
int bp (int a, int n) {
int res = 1;
while (n) {
if (n & 1) res = res * a % mod;
= a * a % mod;
a >>= 1;
n }
return res;
}
// находит обратный элемент как a^(p-2)
int inv (int x) {
return bp(x, mod-2);
}
int c (int n, int k) {
return t[n] * inv(t[k]) % mod * inv(t[n-k]) % mod;
}
Диофантовыми уравнениями называют такие штуки:
Требуется решить их в целых числах, то есть
Подставим в качестве
Одним из решений уравнения и будет
Преимущества этого метода над возведением в степень:
Сам автор почти всегда использует возведение в степень.
1e9+7
).int
не переполняется при сложении.long long
не переполняется при умножении.Кстати,
Пусть нам нужно зачем-то посчитать все те же
Если у нас уже написан inv
, то нам не жалко потратить
После этого мы будем считать
int f[maxn];
[0] = 1;
ffor (int i = 1; i < maxn; i++)
[i] = i*f[i-1] % mod;
f
int r[maxn];
[maxn-1] = inv(f[maxn-1])
rfor (int i = maxn-1; i >= 1; i--)
[i-1] = r[i]*i % mod; r
TODO: техника с сайта емакса.