快速幂
把指数二进制分解,把乘法运算的次数减小到 logn 的级别。
int pow(int x, int y, int p){
int res = 1;
for( ; y; x = (x*x)%p, y >>= 1) if(y&1) res = (res * x) % p;
return res;
}
欧几里得算法
最大公约数
定理:
两个整数的最大公约数等于其中较小的那个数和两数相除余数的最大公约数。
最大公约数(
greatest common divisor
)缩写为
gcd
。
gcd(a,b)=gcd(b,a%b)
证明:
不妨设
a>b
且
r=a%b
,
r
不为0。
假设
d
是
显然等式右边为整数,所以
d|r
,因此
d
也是
假设
d
是
显然
d|a
,因此d也是a,b的公约数
gcd(a,b)=gcd(b,a%b)
得证。
代码:
int gcd(int a, int b){
if(b == 0) return a;
return gcd(b, a % b);
}
//时间复杂度:O(log n)
拓展欧几里得
定理:
对于不完全为
0
的非负整数
证明:
不妨设
a>b,A>B
因为
ax+by=gcd(a,b)
,
gcd(a,b)=gcd(b,a%b)
考虑递归的过程,令
a=b,b=a%b
所以
即:
解得:
代码:
int exgcd(int a, int b, int &x, int &y){
if(b == 0){
x = 1, y = 0;
return a;
}
int GCD = exgcd(b, a%b, x, y);
int xx = x;
x = y, y = xx - a/b * y;
return GCD;
}
//时间复杂度:O(log n)
应用
求乘法逆元
当 gcd(a,b)=1 时,在 modb 的同余系下,有:
所以当
gcd(a,b)=1
时,
a
存在
求解线性同余方程
线性同余方程是最基本的同余方程,“线性”表示方程的未知数次数是一次,即形如:
此方程有解当且仅当
b
能够被
这时,如果
其中
d
是
假如
中国剩余定理
中国剩余定理可以求出以下的一元线性同余方程组中
x
的一个解:
假设整数 m1,m2,...,mn 两两互质,则对任意的整数: a1,a2,...,an ,方程组 (S) 有解,并且通解可以用如下方式构造得到:
设 M=∏ni=1mi ,并设 Mi=Mmi , ti=M−1imodmi
即:
欧拉函数
定义:
在数论,对正整数n,欧拉函数是小于等于n的数中与n互质的数的数目。
求解公式:
phi(n)=n×p1−1p1×p2−1p2×...×pn−1pn
其中
pi
表示
x
的质因数。
性质:
- 不完全积性函数:
ϕ(ab)=ϕ(a)ϕ(b) ,其中 gcd(a,b)=1 。- ∑d|nϕ(d)=n
- 欧拉定理: aϕ(p)≡1modp
-
ϕ(n)=∑i=1n[gcd(i,n)=1]=∑i=1n∑k|n,k|iμ(k)=∑k|nμ(k)nk
代码:
求解单个:
typedef long long ll; bool is[100010]; ll prime[100010], cnt; ll n; ll phi(ll x){ ll ans = x, i; for(i = 1; prime[i] <= x && i <= cnt; i ++){ if(x % prime[i] == 0) ans = ans/prime[i]*(prime[i]-1); while(x % prime[i] == 0) x /= prime[i]; } if(x != 1) ans = ans/x*(x-1); return ans; } void init(){ is[1] = is[0] = 1; for(int i = 2; i <= 100000; i ++){ if(!is[i]) prime[++cnt] = i; for(int j = 1; j <= cnt; j ++){ if(i*prime[j] >= 100000) break; is[i*prime[j]] = 1; if(i % prime[j] == 0) break; } } }
线性筛法:
typedef long long ll; const ll N = 10000000; bool is[N+10]; int prime[N+10], cnt; int phi[N+10]; ll n, ans; void init(){ phi[1] = 1; is[1] = is[0] = 1; for(int i = 2; i <= N; i ++){ if(!is[i]) prime[++cnt] = i, phi[i] = prime[cnt]-1; for(int j = 1; j <= cnt; j ++){ if(i*prime[j] >= N) break; is[i*prime[j]] = 1; if(i % prime[j] == 0){ phi[i*prime[j]] = phi[i] * prime[j]; break; }else phi[i*prime[j]] = phi[i] * (prime[j] - 1); } } }