素数及其性质
素数又称质数。指整数在一个大于 1 1 1 的自然数中,除了 1 1 1 和此整数自身外,没法被其他自然数整除的数。
性质1 有无穷多个素数。
证明: 用反证法。设已知的最大素数为
P
P
P,考虑
S
=
2
×
3
×
5
×
…
×
P
+
1
S=2\times3\times5\times…\times P+1
S=2×3×5×…×P+1
显然所有已知素数都无法整除
S
S
S,所以我们找到了一个更大的素数。
Q.E.D..
\text{Q.E.D..}
Q.E.D..
性质2 对于正整数
p
,
q
p,q
p,q,若
p
p
p 是素数且
p
∤
q
p\nmid q
p∤q,则
p
,
q
p,q
p,q 互素。
证明: 由素数定义知,
p
p
p 的因子为
1
,
p
1,p
1,p。
∵
p
∤
q
,
\because p\nmid q,
∵p∤q,
∴
gcd
(
p
,
q
)
=
1
,
\therefore \gcd(p,q)=1,
∴gcd(p,q)=1,
即
p
,
q
p,q
p,q 互素。
Q.E.D..
\text{Q.E.D..}
Q.E.D..
性质3 对于任意正整数
N
N
N,存在连续的
N
N
N 个合数。
证明: 考虑
(
N
+
1
)
!
+
2
,
(
N
+
1
)
!
+
3
,
(
N
+
1
)
!
+
4
,
.
.
.
,
(
N
+
1
)
!
+
N
(N+1)!+2,(N+1)!+3,(N+1)!+4,...,(N+1)!+N
(N+1)!+2,(N+1)!+3,(N+1)!+4,...,(N+1)!+N
这
N
N
N 个数都是合数。
Q.E.D..
\text{Q.E.D..}
Q.E.D..
性质4 若
p
p
p 是素数,
a
a
a 是小于
p
p
p 的正整数,则
a
p
m
o
d
p
=
1
a^p\mod p= 1
apmodp=1。
证明: 详细证明戳这里。
题目描述 loj10197 \text{loj10197} loj10197
给定两个整数 L , R L,R L,R,求闭区间 [ L , R ] [L,R] [L,R] 中相邻两个质数差值最小的数对与差值最大的数对。当存在多个时,输出靠前的素数对。
输入格式
多组数据。每行两个数 L , R L,R L,R。
输出格式
详见输出样例。
样例输入
2 17
14 17
样例输出
2,3 are closest, 7,11 are most distant.
There are no adjacent primes.
数据范围与提示
对于全部数据, 1 ≤ L ≤ R ≤ 2 31 1≤L≤R≤2^{31} 1≤L≤R≤231, R − L ≤ 1 0 6 R-L≤10^6 R−L≤106。
Solution 10197 \text{Solution 10197} Solution 10197
由于
R
−
L
R-L
R−L 的数值较小,自然想到把
[
L
,
R
]
[L,R]
[L,R] 间的素数筛出,然后找出答案。
对于
[
L
,
R
]
[L,R]
[L,R] 区间的数的质因子集
{
S
}
\{S\}
{S},必有
∣
S
∣
≤
max
R
≈
5
×
1
0
4
|S|≤\sqrt{\max R}≈5\times10^4
∣S∣≤maxR≈5×104先筛出
5
×
1
0
4
5\times10^4
5×104 内的素数,再尝试从
S
S
S 的
⌈
L
S
⌉
\lceil \frac{L}{S} \rceil
⌈SL⌉ 倍开始筛去合数,剩下的就是素数。注意特判
1
1
1。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define reg register
typedef long long ll;
const int inf=1e6+10;
int L,R;
int a[1000010],b[1000010],d[1000010];
int len=0,c,set=0;
int l1,r1,l2,r2,ans1,ans2;
void work(){
memset(b,1,sizeof(b));
for(reg int i=2;i<=inf;++i){
if(b[i]){
b[i]=0;a[++len]=i;
for(reg int j=i+i;j<=inf;j+=i)
b[j]=0;
}
}
}
int main(){
work();
while(scanf("%d%d",&L,&R)!=EOF){
l1=r1=l2=r2=0;ans1=0x3f3f3f3f;ans2=-1;
memset(d,1,sizeof(d));
if(L==1) d[0]=0;
for(reg int i=1;i<=len;++i){
c=L/a[i];
//if(ll(a[i]*c)<(ll)L) ++c;
for(reg int j=c<=1?2:c;j<=R/a[i];++j){
int dd=j*a[i]-L;
if(dd>R-L||dd<0) continue;
d[dd]=0;
}
}
for(reg int i=0;i<=R-L;++i)
if(d[i]){
set=i;
break;
}
if(set==-1){
puts("There are no adjacent primes.");
continue;
}
for(reg int i=set+1;i<=R-L;++i)
if(d[i]){
if(i-set<ans1){
ans1=i-set;
l1=set+L;r1=i+L;
}
if(i-set>ans2){
ans2=i-set;
l2=set+L;r2=i+L;
}
set=i;
}
// for(reg int i=0;i<=R-L;++i)
// printf("%d ",d[i]);
// puts("");
if(!l1&&!r1&&!l2&&!r2)
puts("There are no adjacent primes.");
else
printf("%d,%d are closest, %d,%d are most distant.\n",l1,r1,l2,r2);
}
}
题目描述 loj10198 \text{loj10198} loj10198
原题来自:NOIP 2012 普及组
已知正整数 n n n 是两个不同的质数的乘积,试求出较大的那个质数。
输入格式
输入只有一行,包含一个正整数 n n n。
输出格式
输出只有一行,包含一个正整数 p p p,即较大的那个质数。
样例输入
21
样例输出
7
数据范围与提示
对于 30 % 30\% 30% 的数据, n ≤ 1000 n\leq1000 n≤1000;
对于全部数据, 6 ≤ n ≤ 2 × 1 0 9 6\leq n\leq 2\times10^9 6≤n≤2×109。
Solution 10198 \text{Solution 10198} Solution 10198
由于 n n n 是 2 2 2 个素数之积,所以当我们找到一个较小素数 x x x 使 x ∣ n x|n x∣n 时,另一个素因子就是 n x \frac{n}{x} xn。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define reg register
typedef long long ll;
ll n;
bool b[200000010];
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
void work(){
memset(b,1,sizeof(b));
for(reg ll i=2;i*i<=n;++i){
if(b[i]){
b[i]=0;
if(!(n%i)){
printf("%lld",max(i,n/i));
exit(0);
}
for(reg ll j=i+i;j<=min(n,20000000);j+=i)
b[j]=0;
}
}
}
int main(){
scanf("%lld",&n);
work();
}
题目描述 loj10200 \text{loj10200} loj10200
哥德巴赫猜想:任何大于
4
4
4 的偶数都可以拆成两个奇素数之和。
你的任务是:验证小于
1
0
6
10^6
106 的数满足哥德巴赫猜想。
输入格式
多组数据,每组数据一个
n
n
n。
读入以
0
0
0 结束。
输出格式
对于每组数据,输出形如
n
=
a
+
b
n=a+b
n=a+b,其中
a
,
b
a,b
a,b 是奇素数。若有多组满足条件的
a
,
b
a,b
a,b,输出
b
−
a
b-a
b−a 最大的一组。
若无解,输出 Goldbach's conjecture is wrong.
。
样例输入
8
20
42
0
样例输出
8 = 3 + 5
20 = 3 + 17
42 = 5 + 37
数据范围与提示
对于全部数据, 6 ≤ n ≤ 1 0 6 6\leq n\leq10^6 6≤n≤106。
Solution 10200 \text{Solution 10200} Solution 10200
- 预处理出 1 − n 1-n 1−n 的素数;
- 对于每一个 n n n,枚举 a a a 判断是否合法。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define reg register
int n,s;
int a[100010],b[1000010];
int len=0;
int f[1000010];
void reset(){
memset(b,1,sizeof(b));
for(reg int i=2;i*i<=1000000;++i)
if(b[i]){
a[++len]=i;
for(reg int j=i+i;j<=1000000;j+=i)
b[j]=0;
}
}
void work(int x){
if(!x) return;
if(f[x]){
printf("%d = %d + %d\n",x,f[x],x-f[x]);
return;
}
for(reg int i=2;i<=len/2+1;++i)
if(b[x-a[i]]){
f[x]=a[i];
printf("%d = %d + %d\n",x,f[x],x-f[x]);
return;
}
}
int main(){
memset(f,0,sizeof(f));
reset();
do{
scanf("%d",&s);
work(s);
}while(s);
}
题目描述 loj10201 \text{loj10201} loj10201
Sherlock 有了一个新女友(这太不像他了!)。情人节到了,他想送给女友一些珠宝当做礼物。
他买了
n
n
n 件珠宝。第
i
i
i 件的价值是
i
+
1
i+1
i+1。那就是说,珠宝的价值分别为
2
,
3
,
4
,
.
.
.
,
n
+
1
2,3,4,...,n+1
2,3,4,...,n+1。
Watson 挑战 Sherlock,让他给这些珠宝染色,使得一件珠宝的价格是另一件的质因子时,两件珠宝的颜色不同。并且,Watson 要求他最小化颜色的使用数。
请帮助 Sherlock 完成这个简单的任务。
输入格式
只有一行一个整数 n n n,表示珠宝件数。
输出格式
第一行一个整数
k
k
k,表示最少的染色数;
第二行
n
n
n 个整数,表示第
1
1
1 到第
n
n
n 件珠宝被染成的颜色。若有多种答案,输出任意一种。
样例输入 1
3
样例输出 1
2
1 1 2
样例输入 2
4
样例输出 2
2
2 1 1 2
样例说明
因为 2 2 2 是 4 4 4 的一个质因子,因此第一件珠宝与第三件珠宝的颜色必须不同。
数据范围与提示
对于全部数据, 1 ≤ n ≤ 1 0 5 1\leq n\leq10^5 1≤n≤105。
Solution 10201 \text{Solution 10201} Solution 10201
易证,所有的素数都是互素的。
所以,我们可以把所有的素数全部染成一种颜色,把其他数染成另一种颜色。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define reg register
int n;
int a[100010];
void work(){
memset(a,1,sizeof(a));
for(reg int i=2;i<=n+5;++i)
if(a[i])
for(reg int j=i+i;j<=n+5;j+=i)
a[j]=0;
}
int main(){
scanf("%d",&n);
if(n==1){
puts("1\n1");
exit(0);
}
if(n==2){
puts("1\n1 1");
exit(0);
}
work();
puts("2");
for(reg int i=1;i<=n;++i)
printf("%d ",a[i+1]?1:2);
}
题目描述 luoguP1306 \text{luoguP1306} luoguP1306
对于Fibonacci数列: 1 , 1 , 2 , 3 , 5 , 8 , 13...... 1,1,2,3,5,8,13...... 1,1,2,3,5,8,13...... 大家应该很熟悉吧~~~但是现在有一个很“简单”问题:第 n n n 项和第 m m m 项的最大公约数是多少?
输入格式
两个正整数 n n n 和 m m m。( n , m ≤ 1 0 9 n,m\leq10^9 n,m≤109)
输出格式
f
n
f_n
fn 和
f
m
f_m
fm 的最大公约数。
由于看了大数字就头晕,所以只要输出最后的8位数字就可以了。
输入样例
4 7
输出样例
1
Solution P1306 \text{Solution P1306} Solution P1306
今有结论
gcd
(
f
n
,
f
m
)
=
f
gcd
(
n
,
m
)
\gcd(f_n,f_m)=f_{\gcd(n,m)}
gcd(fn,fm)=fgcd(n,m)
证明: 当
n
=
m
n=m
n=m 时,结论显然成立。不妨设
n
<
m
n< m
n<m,记
f
n
=
a
,
f
n
+
1
=
b
f_n=a,f_{n+1}=b
fn=a,fn+1=b。
则
f
n
+
2
=
a
+
b
f_{n+2}=a+b
fn+2=a+b
f
n
+
3
=
a
+
2
b
f_{n+3}=a+2b
fn+3=a+2b
f
n
+
4
=
2
a
+
3
b
f_{n+4}=2a+3b
fn+4=2a+3b
.
.
.
...
...
f
m
=
a
⋅
f
m
−
n
−
1
+
b
⋅
f
m
−
n
f_m=a·f_{m-n-1}+b·f_{m-n}
fm=a⋅fm−n−1+b⋅fm−n
而
gcd
(
f
n
,
f
m
)
=
gcd
(
f
n
,
a
⋅
f
m
−
n
+
1
+
b
⋅
f
m
−
n
)
\gcd(f_n,f_m)=\gcd(f_n,a·f_{m-n+1}+b·f_{m-n})
gcd(fn,fm)=gcd(fn,a⋅fm−n+1+b⋅fm−n)
∴
gcd
(
f
n
,
f
m
)
=
gcd
(
f
n
,
b
⋅
f
m
−
n
)
\therefore\gcd(f_n,f_m)=\gcd(f_n,b·f_{m-n})
∴gcd(fn,fm)=gcd(fn,b⋅fm−n)。
引理:对于
∀
n
∈
Z
∗
\forall n\in\Z^*
∀n∈Z∗,有
gcd
(
f
n
,
f
n
+
1
)
=
1
\gcd(f_n,f_{n+1})=1
gcd(fn,fn+1)=1。
证明:
gcd
(
f
n
,
f
n
+
1
)
=
gcd
(
f
n
,
f
n
+
f
n
−
1
)
=
gcd
(
f
n
,
f
n
−
1
)
=
gcd
(
f
n
−
1
,
f
n
−
1
+
f
n
−
2
)
=
gcd
(
f
n
−
1
,
f
n
−
2
)
…
=
gcd
(
f
2
,
f
1
)
=
1
\begin{aligned}\gcd(f_n,f_{n+1})&=\gcd(f_n,f_n+f_{n-1})\\ &=\gcd(f_n,f_{n-1})\\ &=\gcd(f_{n-1},f_{n-1}+f_{n-2})\\ &=\gcd(f_{n-1},f_{n-2})\\ &…\\ &=\gcd(f_2,f_1)\\ &=1 \end{aligned}
gcd(fn,fn+1)=gcd(fn,fn+fn−1)=gcd(fn,fn−1)=gcd(fn−1,fn−1+fn−2)=gcd(fn−1,fn−2)…=gcd(f2,f1)=1
∴
\therefore
∴
gcd
(
f
n
,
f
m
)
=
gcd
(
f
n
,
f
m
−
n
)
=
gcd
(
f
n
,
f
m
m
o
d
n
)
\begin{aligned}\gcd(f_n,f_m)&=\gcd(f_n,f_{m-n})\\ &=\gcd(f_n,f_{m\mod n}) \end{aligned}
gcd(fn,fm)=gcd(fn,fm−n)=gcd(fn,fmmodn)
我们发现,这实质就是求解
gcd
(
m
,
n
)
\gcd(m,n)
gcd(m,n) 的过程,
∴
\therefore
∴
gcd
(
f
n
,
f
m
)
=
gcd
(
f
gcd
(
n
,
m
)
,
f
0
)
=
f
gcd
(
n
,
m
)
\begin{aligned}\gcd(f_n,f_m)&=\gcd(f_{\gcd(n,m)},f_0)\\ &=f_{\gcd(n,m)} \end{aligned}
gcd(fn,fm)=gcd(fgcd(n,m),f0)=fgcd(n,m)
2019.12.3 更新
证法二: 我们首先证明
∀
d
∣
i
,
f
d
∣
f
i
(*)
\forall d\mid i,f_d\mid f_i\tag{*}
∀d∣i,fd∣fi(*)
设
f
0
=
0
,
d
f_0=0,d
f0=0,d 是一个正整数。
当
i
=
0
i=0
i=0 时,显然有
f
d
∣
f
i
d
f_d\mid f_{id}
fd∣fid
设
f
d
∣
f
i
d
f_d\mid f_{id}
fd∣fid,我们只需证明
f
d
∣
f
(
i
+
1
)
d
f_d\mid f_{(i+1)d}
fd∣f(i+1)d
注意到
f
r
=
f
2
f
r
−
1
+
f
1
f
r
−
2
=
(
f
2
+
f
1
)
f
r
−
2
+
f
2
f
r
−
3
=
f
3
f
r
−
2
+
f
2
f
r
−
3
=
(
f
2
+
f
3
)
f
r
−
3
+
f
3
f
r
−
4
=
f
4
f
r
−
3
+
f
3
f
r
−
4
=
.
.
.
=
f
r
−
l
+
1
f
l
+
f
r
−
l
f
l
+
1
\begin{aligned}f_r=f_2f_{r-1}&+f_1f_{r-2}\\ &=(f_2+f_1)f_{r-2}&&+f_2f_{r-3}\\ &=f_3f_{r-2}&&+f_2f_{r-3}\\ & &&=(f_2+f_3)f_{r-3}&&+f_3f_{r-4}\\ & &&=f_4f_{r-3}&&+f_3f_{r-4}\\ & &&=...&&\\ & &&=f_{r-l+1}f_l&&+f_{r-l}f_{l+1}\end{aligned}
fr=f2fr−1+f1fr−2=(f2+f1)fr−2=f3fr−2+f2fr−3+f2fr−3=(f2+f3)fr−3=f4fr−3=...=fr−l+1fl+f3fr−4+f3fr−4+fr−lfl+1
令
l
=
i
d
,
r
=
(
i
+
1
)
d
l=id,r=(i+1)d
l=id,r=(i+1)d,那么
f
d
∣
f
l
,
f
d
∣
f
r
−
l
f_d\mid f_l,\quad f_d\mid f_{r-l}
fd∣fl,fd∣fr−l所以
f
d
∣
f
r
f_d\mid f_r
fd∣fr即
f
d
∣
f
(
i
+
1
)
d
f_d\mid f_{(i+1)d}
fd∣f(i+1)d
(
∗
)
(*)
(∗) 式得证。
因为
gcd
(
i
,
j
)
∣
i
,
gcd
(
i
,
j
)
∣
j
\gcd(i,j)\mid i,\quad \gcd(i,j)\mid j
gcd(i,j)∣i,gcd(i,j)∣j所以
f
gcd
(
i
,
j
)
∣
f
i
,
f
gcd
(
i
,
j
)
∣
f
j
,
f_{\gcd(i,j)}\mid f_i,\quad f_{\gcd(i,j)}\mid f_j,
fgcd(i,j)∣fi,fgcd(i,j)∣fj,
f
gcd
(
i
,
j
)
∣
gcd
(
f
i
,
f
j
)
f_{\gcd(i,j)}\mid\gcd(f_i,f_j)
fgcd(i,j)∣gcd(fi,fj)
下面我们证明 K = gcd ( f i , f j ) f gcd ( i , j ) = 1 (**) K=\frac{\gcd(f_i,f_j)}{f_{\gcd(i,j)}}=1\tag{**} K=fgcd(i,j)gcd(fi,fj)=1(**)
采用反证法完成证明。
不妨设
K
≠
1
,
t
=
gcd
(
i
,
j
)
,
t
≠
gcd
(
f
i
,
f
j
)
K\neq 1,\\t=\gcd(i,j),\\t\neq\gcd(f_i,f_j)
K=1,t=gcd(i,j),t=gcd(fi,fj)则一定存在
T
≠
t
,
t
∣
T
,
f
t
∣
f
T
T\neq t,\quad t\mid T,\quad f_t\mid f_T
T=t,t∣T,ft∣fT使
gcd
(
f
i
,
f
j
)
f
T
=
1
\frac{\gcd(f_i,f_j)}{f_T}=1
fTgcd(fi,fj)=1那么
T
∣
i
,
T
∣
j
T\mid i,\quad T\mid j
T∣i,T∣j又因为
T
>
t
T>t
T>t,所以
t
≠
gcd
(
i
,
j
)
t\neq\gcd(i,j)
t=gcd(i,j),矛盾!故
(
∗
∗
)
(**)
(∗∗) 式成立,原命题得证。
于是问题转化成求 f gcd ( n , m ) f_{\gcd(n,m)} fgcd(n,m) 的值。使用矩阵乘法和快速幂完成求解。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define reg register
typedef long long ll;
int a,b;
int n,m;
struct node{
ll a[3][3];
int x,y;
node(){
x=y=0;
memset(a,0,sizeof(a));
}
void pt(){
printf("%lld",a[1][2]);
}
}s,t,ans;
node T(node a,node b){
node c;c.x=a.x;c.y=b.y;
for(reg int i=1;i<=c.x;++i)
for(reg int j=1;j<=c.y;++j)
for(reg int k=1;k<=a.y;++k)
c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%m;
return c;
}
node QT(node a,int b){
if(b<=1) return a;
node c=QT(a,b/2);
if(b%2)
return T(T(c,c),a);
else
return T(c,c);
}
int main(){
scanf("%d%d",&a,&b);
n=std::__gcd(a,b);m=100000000;
if(n<=2){
puts("1");
exit(0);
}
s.x=1;s.y=2;s.a[1][1]=s.a[1][2]=1;
t.x=2;t.y=2;t.a[1][1]=0;t.a[1][2]=t.a[2][1]=t.a[2][2]=1;
ans=T(s,QT(t,n-2));
ans.pt();
}
Miller-Rabin 测试
戳这儿进行预习。
Miller-Rabin 测试基于以下定理。
若
p
p
p 是素数,
x
x
x 是小于
p
p
p 的正整数,且
x
2
m
o
d
p
=
1
x^2\mod p=1
x2modp=1,则
x
=
1
x=1
x=1 或
x
=
p
−
1
x=p-1
x=p−1。
以
n
=
341
n=341
n=341 为例,Miller-Rabin 测试步骤如下:
- 计算得 2 341 − 1 m o d 341 = 1 2^{341-1}\mod 341=1 2341−1mod341=1;
- 将 341 341 341 除以 2 2 2,得到 170 170 170;
- 计算得 2 170 − 1 m o d 341 = 1 2^{170-1}\mod 341=1 2170−1mod341=1;
- 将 170 170 170 除以 2 2 2,得到 85 85 85;
- 计算得 2 85 m o d 341 = 32 ≠ 1 2^{85} \mod341=32\ne1 285mod341=32=1,所以 341 341 341 不是素数( 341 341 341 是伪素数)。
- * 若是素数,则换用 3 3 3 或其他素数重复以上操作。
一般地,我们把 ∀ n \forall n ∀n 有 a ( n − 1 ) m o d n = 1 a^{(n-1)}\mod n=1 a(n−1)modn=1 的合数 n n n 叫做以 a a a 为底的 伪素数。