有理数取模

做题的时候突然发现当初 【数学】学习笔记 漏了有理数取模,但在很多概率期望题里又不会给出提示,于是总结一下,算是对笔记的一个补充吧。


有理数是啥?翻开我们的初中数学课本,发现有理数是整数和分数的总称,所以说所有的有理数 \(q\) 其实可以表示成 \(q=\dfrac{a}{b}\)\(a,b\in \mathbf{Z}\))的形式。

那对有理数取模就是让我们求 \(\dfrac{a}{b}\mod p\)(假设 \(p\) 为质数) 的值咯。

我们可以想,假设这个值为 \(x\),那它是不是满足 \(x\equiv \dfrac{a}{b}\pmod{p}\) 啊。给这个柿子变一下形,得 \(bx\equiv a\pmod{p}\),也就是说,我们找的值其实就是这个同余方程的解啦。

为解这个同余方程,不妨令 \(x=ax_0\),则 \(b(ax_0)\equiv a\pmod{p} \Rightarrow bx_0\equiv 1\pmod{p}\)

我们可以就用 exgcd 求得 \(x_0\),进而求得 \(x\) 啦。

无解的话,不妨考虑:

  • \(p\mid b\),此时若 \(p\mid a\),则同余方程恒成立,有无数组解,而反之不可能成立,方程无解;

  • 反之,则因为 \(p\) 为质数,所以 \(b\)\(p\) 互质,那么 \(bx_0\equiv 1\pmod{p}\) 一定有解。

综上,特判当 \(p\mid b\) 是无解就行了。

如例题:P2613 【模板】有理数取余 其实就是套了个 Trick 嘛,具体实现可参考代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int p = 19260817;
int read()
{
	int x = 0;
	char ch = getchar();
	while(!isdigit(ch) && ch != EOF) ch = getchar();
	while(isdigit(ch)) x = x * 10 + (ch - '0'), x %= p, ch = getchar();
	return x;
}
void print(int num)
{
	if(num > 9) print(num / 10);
	putchar(num % 10 + '0');
}
int x, y;
void exgcd(int a, int b)
{
	if(b == 0)
	{
		x = 1, y = 0;
		return;
	}
	exgcd(b, a % b);
	int z = x;
	x = y;
	y = z - y * (a / b);
}
int a, b;
signed main()
{
	a = read(), b = read();
	if(b == 0) return puts("Angry!"), 0;
	exgcd(b, p);
	x = (x % p + p) % p;
	cout << x * a % p;
	return 0;
}
posted @ 2025-05-15 12:06  cold_jelly  阅读(6)  评论(0)    收藏  举报