数论问题之质数

质数定义

若一个正整数无法被1和它自身之外的任何自然数整除,则称该数为质数(素数),否则该数为合数。

质数的判定用试除法:

1
2
3
4
5
6
7
bool is_prime(int n){
if(n<2) return false;
for(int i=2;i<=sqrt(n);i++){
if(n%i==0) return false;
}
return true;
}

质数的筛选方法:
埃式筛法和线性筛法:链接(之前写过,就不写了)。

质因数分解

算术基本定理:
任何一个不大于1的正整数都能唯一分解为有限个质数的乘积,可写作

​ 其中ci为正整数,pi为质数,满足p11,则说明n为质数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int p[N],c[N],m;//p数组表示n的因子,c数组表示对应的因子的个数
void devide(int n){
memset(c,0,sizeof(c));
m=0;//m记录的多少个因子
for(int i=2;i*i<=n;i++){
if(n%i==0){
p[++m]=i;
while(n%i==0) n/=i,c[m]++;
}
}
if(n>1) c[++m]=n,c[m]++;
for(int i=1;i<=m;i++){
cout<<p[i]<<'^'<<c[i]<<endl;
}
}
int main(){
int n;
cin>>n;
devide(n);
system("pause");
}

poj1845Sumdiv
题意:求A^B^的所有约数之和mod9901.
思路:
把A分解质因数

​ 根据乘法分配律,A^B^的所有约数之和就是:

​ 在使用分治法求sum(p,c)=1+p^1+p^2+p^3+……+p^c
​ 当c为奇数时有偶数项,当c为偶数时有奇数项
​ c为奇数:

​ sum(p,c)=1+p^1+p^(c-1)/2+……+p^(c+1)/2+……+p^c
​ =(1+p^1+……+p^(c-1)/2)+p^(c+1)/2 (1+p^1^+……+p^(c-1)/2)
​ =(1+p^(c+1)/2)
(1+p^1^+……+p^(c-1)/2)
​ =(1+p^(c+1)/2) * sum(p,(c-1)/2)
​ c为偶数:

​ sum(p,c)=1+p^1+p^(c-2)/2+……+p^c/2+……+p^c-1+p^c
​ ==(1+p^c/2) sum(p,c/2-1)+p^c
*代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;
const int mod=9901;
vector<pair<int ,int> > v;
int ksm(int p,int c){
int ans=1;
p%=mod;
while(c){
if(c&1) ans=1ll*ans*p%mod;
p=1ll*p*p%mod;
c>>=1;
}
return ans;
}
int get_sum(int p,int c){
if(!p) return 0;
if(!c) return 1;
if(c&1) return 1ll*(ksm(p,(c+1)/2)+1)*get_sum(p,(c-1)/2)%mod;
else return (1ll*(ksm(p,c/2)+1)*get_sum(p,c/2-1)+ksm(p,c))%mod;
}
int main(){
int a,b;
cin>>a>>b;
for(int i=2;i*i<=a;i++){
if(a%i==0){
int sum=0;
while(a%i==0){
sum++;
a/=i;
}
v.push_back(make_pair(i,sum));
}
}
if(a>1) v.push_back(make_pair(a,1));
int ans=1;
for(int i=0;i<v.size();i++){
int p=v[i].first,c=v[i].second;
ans=1ll*ans*get_sum(p,b*c)%mod;
}
cout<<ans<<endl;
}

poj2689Prime Distance
题意:
给定俩个整数L,R(1<=L<=R<=2^31^,R-L<=10^6^),求闭区间[L,R]内 相邻来个数的差最大是多少,输出这俩个质数。
思路:因为L,R的范围很大不能使用暴力做法,但是R-L的值小,我们可以先筛选出2-sqrt( R)之间的左右质数,然后在用这些质数去筛选L-R内的所有质数,最终没有被标记的就是L-R内的质数。
先处理2-sqrt(2^31^)内的质数,sqrt(2^31^)约等于46340.(可以打表也可以使用线性筛)。
代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include<cstdio>
#include<vector>
#include<iostream>
#include<cstring>
#include<cmath>

using namespace std;
const int M=46430,N=1e6+10,INF=0x7fffffff;
vector<int> p,ans;
bool v[N];
int main(){
memset(v,1,sizeof(v));
for(int i=2;i<=M;i++){
if(v[i]){
p.push_back(i);
for(int j=2;j<=M/i;j++) v[i*j]=0;
}
}
int l,r;
while(cin>>l>>r){
memset(v,1,sizeof(v));
ans.clear();
if(l==1) v[0]=0;
for(int i=0;i<p.size();i++){
for(int j=(l-1)/p[i]+1;j<=r/p[i];j++){
if(j>1) v[p[i]*j-l]=0;
}
}
for(unsigned int i=l;i<=r;i++)
if(v[i-l])
ans.push_back(i);
int minn=INF,maxx=0,x1,x2,y1,y2;
for(int i=0;i<ans.size()-1;i++){
int d=ans[i+1]-ans[i];
if(d<minn){
minn=d;
x1=ans[i];
y1=ans[i+1];
}
if(d>maxx){
maxx=d;
x2=ans[i];
y2=ans[i+1];
}
}
if (!maxx) puts("There are no adjacent primes.");
else printf("%d,%d are closest, %d,%d are most distant.\n", x1, y1, x2, y2);
}
}

CH3101阶乘分解
题意:
给定整数N(1<=N<=10^6^),试把阶乘N!分解质因数,按照算术基本定理的形式输出分解结果中的pi和c1.
思路:
N!的质因数p的个数就是1-N中每个数包含质因数p的个数和,包含质因子p的个数为N/p,接下来计算p^2^的个数为N/p^2^,直到N/(longN/longp),加在一块就是p的个数和。
代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
int isprime[1000000+10];
int prime[1000000+10];
int c;
void Prime(int n) {
memset(isprime,1,sizeof(isprime));
isprime[0]=isprime[1]=0;
for(int i=2;i<=n;i++) {
if(isprime[i]) prime[c++] = i;
for(int j = 0; (j<c && i*prime[j]<=n);j++) {
isprime[i*prime[j]]=0;
if(!(i%prime[j])) break;
}
}
}
int main(){
int n;
cin>>n;
Prime(n);
for(int i=0;i<c;i++) {
int p=prime[i];
int sum=0;
for(int j=n;j>=1;j/=p) sum+=j/p;
printf("%d %d\n",p,sum);
}
}

参考书籍:算法竞赛进阶指南