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!

posted @ 2022-08-08 21:27  A-Problem-Solver  阅读(650)  评论(0编辑  收藏  举报