有理数取模
做题的时候突然发现当初 【数学】学习笔记 漏了有理数取模,但在很多概率期望题里又不会给出提示,于是总结一下,算是对笔记的一个补充吧。
有理数是啥?翻开我们的初中数学课本,发现有理数是整数和分数的总称,所以说所有的有理数 \(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;
}