一.集合
1.基本符号
属于
2.常用集合的字母表示
Z:整数集
N:自然数集
Z+/N*/N+:正整数集
R:实数集
C:虚数集
Q:有理数集
二.整除
1.基本概念
a整除b写作a|b,表示a是b的因子。
(a,b,c····)表示a,b,c····的最大公因数
[a,b,c····]表示a,b,c····的最小公倍数
2.整除定理
(1).
若a|b,则a的绝对值|b的绝对值
证明:
定义一个c,使得b=ac,故得b=(-a)(-c),-b=a(-c)=(-a)c,那么|b|=|ac|=|a||c|
所以|a|||b|
(2).
若a|b,b|c,则a|c
证明:
定义一个d,使得b=ad,那么ad|c,则a|c
(3).
若a|b,a|c,则a|(bx+cy)(x,y为任意实数)
证明:
定义p1,p2,使得b=ap1,c=ap2,那么a|(ap1x,ap2y),a|a(p1x,p2y),则a|(bx+cy)
(4).
若m!=0,a|b,则am|bm
证明:
定义一个c,使得b=ac,那么am|acm,则am|bm
(5).
若(m,a)=1,m|ab,则m|b
证明:
若(m,a)=1,则m一定不是a的因子,m|ab,则m|b
(6).
若ai|c(1<=i<=n),则[a1,a2......,an]|c
(7).
若a,b>0,使得a=bq+r,其中0<=r<b,此外b|a的充分必要条件是r=0
三.同余
1.基本概念
a≡b(mod m)表示a 与b 的除以m的值恒等于。
2.同于定理
(1).
若a≡b(mod m),c≡b(mod m),则a≡c(mod m)
(2).
若a mod p=x,a mod q=x,p,q互质,则a mod pq=x
(3).
d>=1,d|m,若a,a≡b(mod m)≡b(mod m),则a≡b(mod d)
(4).
若d!=0,a≡b(mod m),则da≡db(mod |d|m)
(5).
若ca≡cb(mod m),则a≡b(mod m/(c,m))
(6).
若a≡b(mod mi),则a≡b(mod [m1,m2,.....,mn])
(7).
f(x)=anxn+....+a0
g(x)=bnxn+....b0
ai≡bi(mod m) (0<=i<=n)
若c≡d(mod m),
则f(c)=g(d) (mod m)
f(x)=g(x) (mod m)
四.取模与逆元
1.取模
a+b取模p -->(a+b)%p
a-b取模p -->(a-b+p)%p
a*b取模p -->ab%p
a/b取模p -->a/b%p
2.逆元
定义:
b的逆元等于:b的p-2次方%p
想要完全的推出逆元,我们还需要引进一个新的定理——“费马小定理”
费马小定理:
如果p是一个质数,且a不是p的倍数
则:a的(p-1)次方=1(mod p)
证明:
定义两个集合:A{1,2,.......,p-1}
B{a%p,2a%p,........,(p-1)a%p}
将A集合中的元素相乘得(p-1)!
将B集合中的元素相乘得 (p-1)!a的(p-1)次方%p
因为B集合中是(p-1)个不同的数,同时%p,就有(p-1)种结果,也就是A集合中的数
得出结论:A=B(单只元素,无论排列顺序)
(p-1)!=p-1)!a的(p-1)次方%p
a的(p-1)次方=1(mod p)
五.逆元运用
1.求逆元
题意:
给定一个a,求a mod b的逆元,b=1e9+7;
思路:
运用快速幂算出a的1e9+5次方,每次都要取模b
CD代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e9+7;
long long f(int a,int n){
long long r=1;
while(n){
if(n&1){
r=(r*a)%N;
}
n>>=1;
a=a*(long long)a%N;
}
return r;
}
int main(){
int a;
cin>>a;
cout<<f(a,N-2);
return 0;
}
2.线性求逆元
题意:
给定n,p,求1到n所有整数在模p意义下的乘法逆元。
1)
思路:
首先1的任何次方都等于1,所以第一个输出的一定是1,inv[i]=i的(p-2)次方%p,用到费马小定理和扩展欧几里得算法推出公式inv[i]=(p-p/i)*inv[p%i]%p,具体推法如下:
CD代码:
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int N=3*1e6+5;
int n,p;
ll inv[N];
int main(){
cin>>n>>p;
inv[1]=1;
printf("%lld\n",inv[1]);
for(int i=2;i<=n;i++){
inv[i]=(p-p/i)*inv[p%i]%p;
printf("%lld\n",inv[i]);
}
return 0;
}
2)
思路:
结合欧拉筛把每个数的逆元算出来。对于每个素数求它的逆元,对于除素数意外的数等于两个数相乘为这个数的逆元乘积。
CD代码:
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int N=3*1e6+5;
int n,p;
ll cnt,st[N],q[N],inv[N];
ll f(int n,int x){
ll ans=1;
while(x){
if(x&1){
ans=(ans%p*n)%p;
}
x>>=1;
n=(n%p*n)%p;
}
return ans%p;
}
void ola(int n){
st[1]=1;
inv[1]=1;
printf("%lld\n",inv[1]);
for(int i=2;i<=n;i++){
if(!st[i]){
q[cnt++]=i;
inv[i]=f(i,p-2);
}
for(int j=0;j<cnt&&i*q[j]<=n;j++){
st[i*q[j]]=1;
inv[i*q[j]]=inv[i]*inv[q[j]]%p;
if(i%q[j]==0){
break;
}
}
printf("%lld\n",inv[i]);
}
}
int main(){
cin>>n>>p;
ola(n);
return 0;
}