素数(质数)
素数:在大于1的自然数中,除了1和它本身以外不再有其他因数
(1既不是素数也不是非素数)
判定
- 直接枚举
#include<cstdio>
bool check(int x)
{
if(x<2)
return false;
for(int i=2;i<x;i++)
if(x%i==0)
return false;
return true;
}
int main()
{
int a;
scanf("%d",&a);
printf("%d",check(a));
return 0;
}
- 枚举到sqrt(n)
#include<cstdio>
bool check(int x)
{
if(x<2)
return false;
for(int i=2;i*i<=x;i++)
if(x%i==0)
return false;
return true;
}
int main()
{
int a;
scanf("%d",&a);
printf("%d",check(a));
return 0;
}
- 枚举奇数
#include<cstdio>
bool check(int x)
{
if(x<2)
return false;
if(x==2)
return true;
if(x&1^1)//x为偶数时,条件为true
return false;
for(int i=3;i*i<=x;i+=2)
if(x%i==0)
return false;
return true;
}
int main()
{
int a;
scanf("%d",&a);
printf("%d",check(a));
return 0;
}
- 枚举 6x+1 || 6x-1
#include<cstdio>
bool check(int x)
{
if(x<2)
return false;
if(x==2||x==3)
return true;
if(x&1^1)
return false;
if(x%3==0)
return false;
for(int i=5;i*i<=x;i+=6)
if(x%i==0||x%(i+2)==0)
return false;
return true;
}
int main()
{
int a;
scanf("%d",&a);
printf("%d",check(a));
return 0;
}
分解质因数
唯一分解定理:
(n为任意常数)
- 直接分解
#include<cstdio>
int a[110][110],p[110][110],cnt[110];//a[x][i]表示x分解后的第i个质因数
//p[x][i]表示x分解后的第i个质因数的次方
//cnt[x]表示x分解后一共有多少个质因数
void check(int x)
{
int v=x;
for(int i=2;i*i<=x;i++)//枚举所有的质因数
{
if(v%i==0)
a[x][++cnt[x]]=i;
for(;v%i==0;v/=i)
p[x][cnt[x]]++;//计算质因数的次方
}
if(v>1)//最多只有一个质因数的平方大于x
a[x][++cnt[x]]=v,p[x][cnt[x]]=1;
}
int main()
{
int a;
scanf("%d",&a);
check(a);
return 0;
}
- 优化分解
#include<cstdio>
int a[110][110],p[110][110],cnt[110];
void check(int x)
{
int v=x;
if(v&1^1)//除2之外的其他正偶数都不是质数
a[x][++cnt[x]]=2;
for(;v&1^1;v>>=1)
p[x][cnt[x]]++;
for(int i=3;i*i<=x;i+=2)
{
if(v%i==0)
a[x][++cnt[x]]=i;
for(;v%i==0;v/=i)
p[x][cnt[x]]++;
}
if(v>1)
a[x][++cnt[x]]=v,p[x][cnt[x]]=1;
}
int main()
{
int a;
scanf("%d",&a);
check(a);
return 0;
}
- 再次优化
#include<cstdio>
int a[110][110],p[110][110],cnt[110];
void check(int x)
{
int v=x;
if(v&1^1)//排除2
a[x][++cnt[x]]=2;
for(;v&1^1;v>>=1)
p[x][cnt[x]]++;
if(v%3==0)//排除3
a[x][++cnt[x]]=3;
for(;v%3==0;v/=3)
p[x][cnt[x]]++;
for(int i=5;i*i<=x;i+=4)//从5开始
{
if(v%i==0)
a[x][++cnt[x]]=i;
for(;v%i==0;v/=i)
p[x][cnt[x]]++;
i+=2;
if(v%i==0)
a[x][++cnt[x]]=i;
for(;v%i==0;v/=i)
p[x][cnt[x]]++;
}
if(v>1)
a[x][++cnt[x]]=v,p[x][cnt[x]]=1;
}
int main()
{
int a;
scanf("%d",&a);
check(a);
return 0;
}
埃氏筛法
#include<cstdio>
int b[100010],pr[100010],tp;//b[i]记录i是否是质数
//pr[i]记录从小到大的所有质数
void check(int x)
{
b[0]=b[1]=0;
for(int i=2;i<=x;i++)
b[i]=1;
for(int i=2;i<=x;i++)
{
if(!b[i])
continue;
pr[++tp]=i;
for(int j=i<<1;j<=x;j+=i)
b[j]=0;
}
}
int main()
{
int a;
scanf("%d",&a);
check(a);
return 0;
}
线性筛法
#include<cstdio>
int b[100010],pr[100010],tp;
void check(int x)
{
b[0]=b[1]=0;
for(int i=2;i<=x;i++)
b[i]=1;
for(int i=2;i<=x;i++)
{
if(b[i])
pr[++tp]=i;
for(int j=1;j<=tp&&pr[j]*i<=x;j++)//pr[j]<=i
{
b[pr[j]*i]=0;
if(i%pr[j]==0)//(核心)为了避免重复排除,确保每排除一个数都是根据它的最小质因数即pr[j]
break;
}
}
}
int main()
{
int a;
scanf("%d",&a);
check(a);
return 0;
}