本文初写于 2019-03-07 19:37:32
因为讲课需要,这一周先跳到数论这一章进行学习。
数论使我意识到数学分析真的是有用处的。
唯一分解定理,又名算数基本定理。表述:若一个自然数N不为质数,那么它一定可以分解成有限个质数的乘积,且有唯一等式N=(P_1^{a_1}P_2^{a_2}P_3^{a_3}......P_n^{a_n}),这里(P_1<P_2<P_3<......<P_n)均为质数,(a_i)均为整数。
欧几里德算法,又名辗转相除法,是求最大公约数的一种算法。具体操作是用较大数a对较小数b取余得c,用b对余数c取余得余数d,用c对d取余得e......当所得余数为0时,所用的除数即是最大公约数。
int gcd(int a,int b){//求最大公约数
return b==0?a:gcd(b,a%b);
//刘汝佳说这里不必考虑栈溢出问题
}
int lcm(int a,int b){//求最小公倍数
return a/gcd(a,b)*b;
//先除再乘防止超出int
}
证明参考自悟道人生
假设:
- m,n为整数
- a,b分别是m除以n的商和余数,即m=na+b,即b=m-na。
- gcd(m,n)表示m和n的最大公约数。
求证:gcd(m,n)=gcd(n,b)
先导知识:
整除性推论一:若a能被b整除(a=tb),则如果k为正整数,则ka也能被b整除(ka=ktb)。
整除性推论二:若a能被c整除,b也能被c整除,则(a±b)也能被c整除。
证明:
设c=gcd(m,n) , d=gcd(n,b)
∵ c为m,n的最大公约数
∴ m,n整除c
又∵ 推论一
∴ na整除c
又∵ 推论二
∴ m-na整除c
又∵ b=m-na
∴ c被n,b整除
∴ c为n,b的公约数
又∵ d为n,b的最大公约数
∴ c ≤ d (结论一)
同理,
∵ d为n,b的最大公约数
∴ n,b整除d
又∵ 推论一
∴ na整除d
又∵ 推论二
∴ b+na整除d
又∵ m=na+b
∴ d被m,n整除
∴ d为m,n的公约数
又∵ c为m,n的最大公约数
∴ d ≤ c (结论二)
综上,c=d,即gcd(m,n)=gcd(n,b)
扩展欧几里德算法:何为扩展?一是,该算法保留了欧几里得算法的本质,可以求a与b的最大公约数。二是,已知a, b求解二元一次方程ax+by =gcd(a, b)的一组解(x,y)
ll exgcd(ll a,ll b,ll& x,ll& y){//在gcd基础上求了一组x和y
if(!b){
x=1;
y=0;
return a;
}
ll d=exgcd(b,a%b,y,x);
y-=x*(a/b);
return d;
}
证明参考自午夜阳光~
求证:存在整数 x , y 使得 gcd(a,b)=ax+by
证明:
当b=0时,gcd(a,b)=a,带入方程得x=1,y=0
当b≠0时,设(ax_1+by_1=gcd(a,b))
(=gcd(b,a\%b))
(=bx_2+(a\%b)y_2)
∵ (a\%b=a-lfloorfrac ab
floor b)
∴ (ax_1+by_1=bx_2+(a-lfloorfrac ab
floor b)y_2)
(=bx_2+ay_2-lfloorfrac ab
floor by_2)
(=ay_2+b(x_2-lfloorfrac ab
floor y_2))
∴ (x_1=y_2) , (y_1=x_2-lfloorfrac ab
floor y_2)
应用:
1.求解ax+by=c形式的不定方程
(1)前导知识:求解ax+by=gcd(a,b)形式的不定方程
已求得ax+by=gcd(a,b)的任意一组解x0和y0,则有:
x = x0 + b/(a,b)*k (k∈Z)
y = y0 - a/(a,b)*k (k∈Z)
证明:
任取另外一组解(x1,,y1),则有ax0+by0=gcd(a,b)=ax1+by1
变形得a(x0-x1)=b(y1-y0)
设g=gcd(a,b),a1=a/g,b1=b/g,则有a1(x0-x1)=b1(y1-y0)
因为g≥0,所以a1与b1互素,所以可以设(y1-y0)=ka1,(x0-x1)=kb1
所以有y1-y0=ka1=ka/g => y1=y0+ka/g
同理有x0-x1=kb1=kb/g => x1=x0-kb/g
(因为k∈Z,所以+-号同时变更后这俩等式与定义中等式相同)
(2)推广来求ax+by=c形式的不定方程
设a,b,c均为整数,g=gcd(a,b),先求得ax+by=g的一组解(x0,y0),则当c为g的倍数时ax+by=c的一组解为(cx0/g,cy0/g),再利用(1)中所推导的两公式求得其他解;当c不是g的倍数时则无解
埃氏筛法:构造1~n的素数表
int m=sqrt(n+0.5);
memset(vis,0,sizeof(vis));
for(int i=2;i<=n;i++)
if(!vis[i])
for(int j=i*i;j<=n;j++) //i*i之前的数已经在i更小时遍历过
vis[i]=1;
大约十个数里有一个素数。
欧拉筛法:筛选合数时,保证每个合数只会被它的最小质因数筛去。所以每个数只会被检查一遍,算法时间复杂度降到O(n)
const int maxn=1000;
bool number[maxn+5];
int prime[maxn+5];
void isprime(){
int i,j,cnt=0;
memset(number,true,sizeof(number));
memset(prime,0,sizeof(prime));
for(int i=2;i<=maxn;i++){
if(number[i]) prime[cnt++]=i;
for(j=0;j<cnt&&prime[j]*i<=maxn;j++){
number[prime[j]*i]=false;
if(i%prime[j]==0) break;
//保证每个合数只会被它的最小质因数筛去
//因此每个数只会被标记一次
}
}
}
对if (i % prime[j] == 0)的理解:
∵ i % prime[j] == 0
∴ i为prime[j]的合数
∴ i * 其他数 也为prime[j]的合数
∴ i * prime[j+1],prime[j+2].....prime[j+n]结果也为prime[j]的合数
∴ i % prime[j] == 0时break
快速幂取模:在快速幂的基础上添加了取模的功能
long long pow_mod(long long a,long long b,long long c){
long long ans=1;
while(b){
if(b&1) ans=(ans*a)%c;
a=a*a%c;
b>>=1;
}
return ans;
}