Нехай ways(x, y) позначає кількість шляхів на матриці з клітинки до клітинки (1 + x, 1 + y). Тоді
Кількість шляхів з клітинки до клітинки , що проходять через спеціальну комірку , дорівнює ways(x - 1, y - 1) \cdot ways(n - x, m - y). Помноживши це число на , отримаємо сумарну силу всіх шляхів, які проходять через комірку .
Залишається просумувати сили всіх шляхів, що проходять через спеціальні комірки. Відповідь буде рівна сумі:
Приклад
У наведеному прикладі задані k = 2 спеціальні комірки.
Рівно один шлях проходить через комірку з силою .
Рівно один шлях проходить через комірку з силою .
Таким чином, загальна сила дорівнює 4 + 7 = 11.
Реалізація алгоритму
Оголосимо масиви:
містить факторіали чисел за модулем ,
factinv містить обернені значення до цих факторіалів за модулем :
#define MAX 800001
ll fact[MAX], factinv[MAX];Функція pow обчислює степінь числа за модулем: x^n~mod~p.
ll pow(ll x, ll n, ll p)
{
if (n == 0) return 1;
if (n % 2 == 0) return pow((x * x) % p, n / 2, p);
return (x * pow(x, n - 1, p)) % p;
}Функція inverse знаходить число, обернене до за простим модулем . Оскільки — просте число, то згідно з малою теоремою Ферма виконується рівність:
Його можна переписати у вигляді (x \cdot x^{p-2})~mod~p = 1, звідки слідує, що оберненим до є число x^{p-2}~mod~p.
ll inverse(ll x, ll p)
{
return pow(x, p - 2, p);
}Функція Cnk обчислює біноміальний коефіцієнт за формулою:
ll Cnk(int n, int k)
{
return ((fact[n] * factinv[k]) % MOD * factinv[n - k]) % MOD;
}Функція ways обчислює кількість шляхів на ґратці розміром n \times m з клітинки до клітинки . Оскільки будь-який шлях між цими точками має довжину n + m і містить рівно горизонтальних сегментів, кількість шляхів дорівнює C_{n+m}^m.
ll ways(int n, int m)
{
return Cnk(n + m, m);
}Основна частина програми. Заповнюємо масиви факторіалів і обернених факторіалів factinv.
fact[0] = 1;
for (i = 1; i < MAX; i++)
fact[i] = (fact[i - 1] * i) % MOD;
factinv[0] = 1;
for (i = 1; i < MAX; i++)
factinv[i] = inverse(fact[i], MOD);Послідовно обробляємо тестів.
scanf("%d", &tests);
while (tests--)
{Зчитуємо дані поточного тесту.
scanf("%d %d %d", &n, &m, &k);Сумарну отриману силу зберігаємо в змінній .
res = 0;Обробляємо спеціальних комірок.
for (i = 0; i < k; i++)
{
scanf("%d %d %d", &x, &y, &p);
res = (res + (ways(x - 1, y - 1) *
ways(n - x, m - y)) % MOD * p) % MOD;
}Виводимо відповідь для поточного тесту.
printf("%lld\n", res);
}