数论:质数与约数
摘自《算法竞赛进阶指南》。
数论
1.质数
质数的判定
试除法
bool is_prime(int n){
for(int i=2;i<=sqrt(n);i++)
if(n%i==0)return false;
return true;
}
质数的筛选
(1).Eratosthenes筛法
void primes(int n){
memset(v,0,sizeof(v));//合数标记
for(int i=2;i<=n;i++){
if(v[i])continue;
cout<<i<<endl;//i是质数
for(int j=i;j<=n/i;j++)
v[i*j]=1;
}
}
(2).线性筛法
int v[N],prime[N];
void primes(int n){
memset(v,0,sizeof(v));//最小质因子
m=0;//质数数量
for(int i=2;i<=n;i++){
if(v[i]==0){//i是质数
v[i]=i;
prime[++m]=i;
}
//给当前的数i乘上一个质因子
for(int j=1;j<=m;j++){
//i有比prime[j]更小的质因子,或者超出n的范围
if(prime[j]>v[i]||prime[j]>n/i)
break;
//prime[j]是合数i*prime[j]的最小质因子
v[i*prime[j]]=prime[j];
}
}
for(int i=1;i<=m;i++)
cout<<prime[i]<<endl;
}
质因数分解
(1).算数基本定理:任何一个大于1的正整数都能唯一分解为有限个质数的乘积
(2).试除法
void divide(int n){
m=0;
for(int i=2;i<=sqrt(n);i++)
if(n%i==0){//i是质数
p[++m]=i,c[m]=0;
while(n%i==0)n/=i,c[m]++;//除掉所有的i
}
}
if(n>1)//n是质数
p[++m]=n,c[m]=1;
for(int i=1;i<=m;i++)
cout<<p[i]<<'^'<<c[i]<<endl;
}
2.约数
求N的正约数集合:试除法
int factor[1600],m=0;
for(int i=1;i*i<=n;i++){
if(n%i==0){
factor[++m]=i;
if(i!=n/i)
factor[++m]=n/i;
}
}
for(int i=1;i<=m;i++)
cout<<factor[i]<<endl;
求1~N每个数的正约数集合:倍数法
vector<int>factor[500010];
for(int i=1;i<=n;i++)
for(int j=1;j<=n/i;j++)
factor[i*j].push_back(i);
for(int i=1;i<=n;i++){
for(int j=0;j<factor[i].size();i++)
printf("%d ",factor[i][j]);
puts("");
}
最大公约数
定理:gcd(a,b)*lcm(a,b)=a*b
九章算术·更相减损术
(1).gcd(a,b)=gcd(b,a-b)=gcd(a,a-b)
(2).gcd(2a,2b)=2gcd(a,b)
欧几里得算法:gcd(a,b)=gcd(b,a mod b)
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
互质与欧拉函数
互质:gcd(a,b)=1
欧拉函数:φ(N)
N=p1c1p2c2...pmcm
φ(N)=N((p1-1)/p1)((p2-1)/p2)...((pm-1)/pm)
int phi(int n){
int ans=n;
for(int i=2;i<=sqrt(n);i++)
if(n%i==0){
ans=ans/i*(i-1);
while(n%i==0)n/=i;
}
if(n>1)ans=ans/n*(n-1);
return ans;
}
性质1~2
(1).n>1,1~n中与n互质的数的和为nφ(n)/2
(2).若gcd(a,b)=1,则φ(ab)=φ(a)φ(b)
积性函数:若gcd(a,b)=1,有f(ab)=f(a)*f(b),那么称函数f为积性函数
性质3~6
(3).f(n)=f(p1c1)f(p2c2)...f(pmcm)
(4).若p|n且p2|n,则φ(n)=φ(n/p)*p
(5).若p|n但p2|n,则φ(n)=φ(n/p)*(p-1)
(6).Σd|nφ(d)=n
以上结论均不给出证明。