复习数学知识
快速幂
long long qbow(long long a, long long b, long long p){
long long res=1;
while(b){
if(b&1)res=res*a%p;
a=a*a%p;
b>>=1;
}
return res;
}
最大公约数(还是记一下吧)
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
扩展欧几里得算法(Extended Euclidean algorithm, EXGCD),常用于求
\(ax+by=gcd(a,b)\) 的一组可行解.
int exgcd(int a, int b, int &x, int &y){
if(!b){
x=1;
y=0;
return a;
}
int d=exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-(a/b)*y;
return d;
}
费马小定理:设 \(p\) 是素数。对于任意整数 \(a\) 且 \(p \nmid a\),都有
\[a^{p-1} \equiv 1 \pmod{p}
\]
设\(p\)是素数.对于任意整数\(a\),都成立
\[a^{p}\equiv a\pmod p
\]
欧拉定理:对于整数\(m>0\)和整数\(a\),且\(gcd(a,m)=1\)有
\[a^{\varphi(m)}\equiv 1\pmod{m}
\]
,其中,\(\varphi(n)\)为 欧拉函数.
求模逆元:利用扩展欧几里得算法或快速幂法,可以在\(O(\log m)\)时间内求出单个整数的逆元.
扩展欧几里得算法
// Extended Euclidean algorithm.
void exgcd(int a,int b,int& x,int& y){
if(!b){
x=1;
y=0;
}
else{
exgcd(b,a%b,y,x);
y-=a/b*x;
}
}
// Returns the modular inverse of a modulo m.
// Assumes that gcd(a, m) = 1, so the inverse exists.
int inverse(int a,int m){
int x,y;
exgcd(a,m,x,y);
return(x%m+m)%m;
}
(但是一般都用快速幂吧,mod一般都是质数啥的)
快速幂:
// Binary exponentiation.
int qpow(int a, int b,int m){
long long res=1;
while(b){
if(b&1)res=res*a%m;
a=a*a%m;
b>>=1;
}
return res;
}
// Returns the modular inverse of a prime modulo p.
int inverse(int a,int p){return qpow(a,p-2,p);}
线性同余方程:
设 𝑎,𝑏,𝑛
a,b,n 为整数,𝑥
x 为未知数,那么,形如
\[ax\equiv b\pmod n
\]
的方程称为 线性同余方程(linear congruence equation).
// Extended Euclidean Algorithm.
// Finds integers x, y such that a*x + b*y = gcd(a, b),
// and returns gcd(a, b).
int exgcd(int a,int b,int& x,int& y){
if(!b){
x=1;
y=0;
return a;
}
else{
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
}
// Solves the linear congruence equation:
// a * x ≡ b (mod n), where n > 0.
// Returns the smallest non-negative solution x,
// or -1 if there is no solution.
int solve(int a,int b,int n){
int x,y;
int d=exgcd(a,n,x,y);
if(b%d)return -1;
n/=d;
return ((long long)x*(b/d)%n+n)%n;
}
中国剩余定理:
LL CRT(int k, LL* a, LL* r) {
LL n = 1, ans = 0;
for (int i = 1; i <= k; i++) n = n * r[i];
for (int i = 1; i <= k; i++) {
LL m = n / r[i], b, y;
exgcd(m, r[i], b, y); // b * m mod r[i] = 1
ans = (ans + a[i] * m * b % n) % n;
}
return (ans % n + n) % n;
}
阶乘以及阶乘逆元:
fac[0] = 1;
for (int i = 1; i <= k; i++) fac[i] = fac[i - 1] * i % MOD;
inv[k] = qpow(fac[k], MOD - 2);
for (int i = k - 1; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1) % MOD;
找不到lucas算组合数的板子了。。。找不到算了
浙公网安备 33010602011771号