知识点
因数和倍数的性质
a ∣ b a|b a∣b在数学中表示a是b的因数。
关于符号"|",有以下性质:
- 如果 a ∣ b a|b a∣b则有 − a ∣ b -a|b −a∣b , a ∣ − b a|-b a∣−b , ∣ a ∣ ∣ ∣ b ∣ |a| | |b| ∣a∣∣∣b∣
推导过程: a ∣ b a|b a∣b就是 b / a = k b/a=k b/a=k,在正数与负数的除法中,改变一个整除算式中的数前的正负号,不过改变商的正负号,依然能整除,因此此性质成立。- 如果 m ≠ 0 , a ∣ b m\neq0,a|b m=0,a∣b则有 m a ∣ m b ma|mb ma∣mb
推导过程: a ∣ b a|b a∣b就是 b / a = k b/a=k b/a=k, m a ∣ m b ma|mb ma∣mb就是 m b / m a = k mb/ma=k mb/ma=k,根据除法商不变的性质:除数和被除数同时乘或除以相同的数(0除外),商不变,可知此性质成立。- 如果 a ∣ b , b ∣ c a|b,b|c a∣b,b∣c则有 b ∣ c b|c b∣c
推导过程: a ∣ b = 1 a ∣ a x , b ∣ c = a x ∣ a x y , x = b / a , y = c / b a|b=1a|ax,b|c=ax|axy,x=b/a,y=c/b a∣b=1a∣ax,b∣c=ax∣axy,x=b/a,y=c/b则 a ∣ c = a ∣ a x y a|c=a|axy a∣c=a∣axy,显然 a x y % a = 0 axy\%a=0 axy%a=0- 如果 a ∣ b , a ∣ c a|b,a|c a∣b,a∣c则有 a ∣ ( b x + c y ) a|(bx+cy) a∣(bx+cy)(x,y为任意自然数)
推导过程: a ∣ b = 1 a ∣ a n , a ∣ c = 1 a ∣ a m , n = b / a , m = c / a a|b=1a|an,a|c=1a|am,n=b/a,m=c/a a∣b=1a∣an,a∣c=1a∣am,n=b/a,m=c/a则 a ∣ ( b x + c y ) = a ∣ ( a n x + a m y ) = a ∣ a ( n x + m y ) a|(bx+cy)=a|(anx+amy)=a|a(nx+my) a∣(bx+cy)=a∣(anx+amy)=a∣a(nx+my),显然 a ( n x + m y ) % a = 0 a(nx+my)\%a=0 a(nx+my)%a=0- 如果 ( m , a ) = 1 , m ∣ a b (m,a)=1,m|ab (m,a)=1,m∣ab则有 m ∣ b m|b m∣b
推导过程: ( m , a ) = 1 (m,a)=1 (m,a)=1说明 m ∣ a b m|ab m∣ab与a一点关系都没有,则 m ∣ a b = m ∣ a m k , m ∣ b = m ∣ m k m|ab=m|amk,m|b=m|mk m∣ab=m∣amk,m∣b=m∣mk,显然 m k % m = 0 mk\%m=0 mk%m=0- 有一个集合a长度为n,如果 a i ∣ c , ( 1 ≤ i ≤ n ) a_i|c,(1\leq i \leq n) ai∣c,(1≤i≤n)则有 [ a 1 , a 2 , . . . , a n ] ∣ c [a_1,a_2,...,a_n]|c [a1,a2,...,an]∣c
推导过程: a i ∣ c a_i|c ai∣c说明c是所有 a i a_i ai的倍数,也就是它们的公倍数,一些数的公倍数是这些数的最小公倍数的倍数,因此此性质成立- 如果 a = b q + r a=bq+r a=bq+r则 a ∣ b a|b a∣b的充分必要条件为 r = 0 r=0 r=0
推导过程: a = b q + 1 − > a / b = q . . . . . . r , r = 0 a=bq+1->a/b=q......r,r=0 a=bq+1−>a/b=q......r,r=0则 a = b q + 1 − > a / b = q a=bq+1->a/b=q a=bq+1−>a/b=q,显然此性质成立
取模的四则运算
加法:
( A + B ) % m o d = ( ( A % m o d ) + ( B % m o d ) ) % m o d (A + B) \% mod = ((A \% mod) + (B \% mod)) \% mod (A+B)%mod=((A%mod)+(B%mod))%mod
乘法:
( A ∗ B ) % m o d = ( ( A % m o d ) ∗ ( B % m o d ) ) % m o d (A * B) \% mod = ((A \% mod) * (B \% mod)) \% mod (A∗B)%mod=((A%mod)∗(B%mod))%mod
减法(由于在进行减法运算后结果可能是负数,因此需要加上一个mod后再取模):
( A − B ) % m o d = ( ( A % m o d ) − ( B % m o d ) + m o d ) % m o d (A - B) \% mod =((A \% mod) - (B \% mod) +mod) \% mod (A−B)%mod=((A%mod)−(B%mod)+mod)%mod
除法运算取模是不是也和上面的取模运算一样是
( A / B ) % m o d = ( ( A % m o d ) / ( B % m o d ) ) % m o d (A / B) \% mod = ((A \% mod) / (B \% mod)) \% mod (A/B)%mod=((A%mod)/(B%mod))%mod呢?
答案是否定的,除以一个数可以看成乘这个数的倒数,这个数也叫做逆元,x的逆元记作 i n v ( x ) , x − 1 inv(x),x^{-1} inv(x),x−1。.
所以 ( A / B ) % m o d = ( ( A % m o d ) ∗ ( B − 1 % m o d ) ) % m o d (A / B) \% mod = ((A \% mod) * (B^{-1} \% mod)) \% mod (A/B)%mod=((A%mod)∗(B−1%mod))%mod
逆元的定义和意义
数学上认为mod就是在一个环上做运算,如:x mod 5,认为是在下图中做运算,可是要是运算数中出现分数,并不在环上怎么办?
分数可以看成除法,除以一个数可以看成乘这个数的倒数,关于取模的倒数叫逆元,x的逆元记作 i n v ( x ) , x − 1 inv(x),x^{-1} inv(x),x−1。
要使 ( a ∗ a − 1 ) % p = 1 (a*a^{-1}) \% p=1 (a∗a−1)%p=1, a % p = a − 1 % p a \% p = a^{-1} \% p a%p=a−1%p
逆元的计算
根据费马小定理得知:
(p为质数,a不是p的倍数)
a p − 1 % p = 1 a^{p-1} \% p=1 ap−1%p=1
经过变形可得
( a ∗ a p − 2 ) % p = 1 (a*a^{p-2}) \% p=1 (a∗ap−2)%p=1
与 ( a ∗ a − 1 ) % p = 1 (a*a^{-1}) \% p=1 (a∗a−1)%p=1相似
因此 a − 1 = a p − 2 a^{-1}=a^{p-2} a−1=ap−2
题目
求逆元
时间限制:1秒 内存限制:128M
题目描述
输入a,b= 1 0 9 + 7 10^9+7 109+7,求 a % b a\%b a%b时inv(a)
样例输入
3
样例输出
333333336
代码
用公式解答即可
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
long long mod=1e9+7,a;
long long fast_pow(long long a,long long b){
long long fac=1;
while(b>0){
if(b&1){
fac*=a;
fac%=mod;
}
a=a*a;
a%=mod;
b>>=1;
}
return fac%mod;
}
int main() {
scanf("%lld",&a);
printf("%lld",fast_pow(a,mod-2));
return 0;
}
线性求逆元
时间限制:1秒 内存限制:128M
题目描述
给定n,p,求1到n所有整数在模p意义下的乘法逆元。
样例输入
10 13
样例输出
1
7
9
10
8
11
2
5
3
4
思路
(p/x向下取整)
i n v ( x ) inv(x) inv(x)还等于 ( p − p / x ) ∗ i n v ( p % x ) (p-p/x)*inv(p\%x) (p−p/x)∗inv(p%x)
可用此式子递推求逆元,时间复杂度O(n)。
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int n,p;
long long inv[5000005];
int main(){
scanf("%d %d",&n,&p);
inv[1]=1;
printf("%din",inv[1]);
for(int i=2;i<=n;i++){
inv[i]=(p-p/i)*inv[p%i]%p;
printf("%d\n", inv[i]);
}
return 0;
}