OI loves Math(二)——有理数取模
在一些期望值的题目里,经常会遇到这么一句话:
输出期望值模 $ 998244353 $ 的结果。
然后你就万脸懵逼了,分数怎么取模?
别急!
看这个有理数取余,它里面直接给出了定义:
这个值被定义为 $ bx \equiv a \ (mod \ p) $ 的解。
但问题来了,怎么求出 $ x $ 呢?
反推回去呗!
Part 1 $ x $
$ x = a \div b = a \times \frac{1}{b} $。
但这不还是成小数了吗?
想想倒数的定义:
若 $ xy = 1 $ ,则 $ x, y $ 互为倒数。
我们这也一样,也就是说,在模 $ 10 $ 意义下,$ 3 $ 和 $ 7 $ 互为倒数,也称作逆元。
但是怎么求出 $ b $ 的逆元呢?
Part 2 $ b $ 的逆元
第一种 费马小定理
如果 $ p $ 是一个质数,而整数 $ a $ 不是 $ p $ 的倍数,则有 $ a ^{p - 1} \equiv 1 \ (mod \ p) $。——百度
\[\because a ^{p - 1} \equiv 1 \ (mod \ p)
\]
\[\therefore a^{p - 2} \equiv \frac{1}{a}
\]
懂了吧?
第二种 $ ExGcd $
先咕着,日后再更。
Part 3 代码
注意这里 $ A, B $ 很大,需要用高精除法取一下模。
#include <bits/stdc++.h>
using namespace std;
char A[10005], B[10005];
const long long mod = 19260817;
long long qpow(long long base, long long exp, long long mod) {
long long ans = 1;
while (exp) {
if (exp & 1) {
ans = (ans * base) % mod;
}
exp >>= 1;
base = (base * base) % mod;
}
return ans % mod;
}
int main() {
fgets(A, 1048576, stdin);
fgets(B, 1048576, stdin);
int n = strlen(A), m = strlen(B);
long long a = 0, b = 0;
for (int i = 0; i < n; i++) {
a = (a * 10 + (A[i] - '0')) % mod;
}
for (int i = 0; i < m; i++) {
b = (b * 10 + (B[i] - '0')) % mod;
}
if (!b) {
printf("Angry!");
} else {
long long b_inv = qpow(b, mod - 2, mod);
printf("%lld", (a * b_inv) % mod);
}
return 0;
}
Bye!