质数
概念
对于数x,除了1和x,不可被其他任何数整除。
线性筛
埃式筛是一个O(NloglogN)求素数表的算法
这里不介绍。
线性筛可以在O(n)的时间内求出素数表(1~n内所有素数)。
线性筛中,记录数的最小素数,每个数就只会被他筛掉一次,所以时间复杂度为O(n)。
根据代码。
code
#include<bits/stdc++.h>
using namespace std;
int n,tot,m=0;
int minp[10000010]={},prime[10000010]={};
void make()
{
for(int i=2;i<=n;++i)
{
if (!minp[i])//之前从未被筛就记录素数
{
prime[++m]=i;
minp[i]=i;
}
for(int j=1;j<=m;++j)//枚举每个素数
{
if (prime[j]>minp[i]||prime[j]*i>n) break;
//如果枚举的已经不是最小素数了,或者超出范围,就结束,相当于剪枝。
minp[i*prime[j]]=prime[j];
}
}
return ;
}
int main()
{
scanf("%d%d",&n,&tot);
make();
int x;
for(int i=1;i<=tot;++i)
{
scanf("%d",&x);
if (minp[x]==x) printf("Yes\n");
else printf("No\n");
}
return 0;
}
质因数分解
唯一分解定理
对于每一个数n,都可以唯一地分解。
n=p1^c1*p2^c2*p3^c3……px^cx。
如何求出所有的p与c?
通过线性筛和试除法可以解决。
扫描1~n^(1/2)每个素数,试除即可
code
#include<bits/stdc++.h>
using namespace std;
int n,m=0;
int prime[10010]={},cnt[10010]={};
int main()
{
scanf("%d",&n);
for(int i=2;i<=sqrt(n);++i)//枚举
{
if (!(n%i))//找到质因子
{
prime[++m]=i;
while (!(n%i))n/=i,++cnt[m];//处理n。
}
}
if (n!=1) prime[++m]=n,++cnt[m];//n为质数的情况
for(int i=1;i<=m;++i)
printf("%d %d\n",prime[i],cnt[i]);
return 0;
}
水题
题目描述
对N!进行质因子分解。
N<=10^6.
解析
对于N!
如果通过每个数进行分解的话,是O(N^(3/2))。
但对于阶乘,我们可以枚举每个质数p,至少包含一个p的倍数一定有一个p。那么p^2的倍数每个包含两个p,那么在p的倍数的基础上再加上一,p^3……p^n也一样。
那么N!中质因数p的个数就是N/p+N/(p^2)+……
复杂度为O(nlogn)的。
code
#include<bits/stdc++.h>
using namespace std;
int n,m=0;
int prime[10010]={},minp[10010]={},cnt[10010]={};
void make()
{
for(int i=2;i<=n;++i)
{
if (!minp[i])
{
minp[i]=i;
prime[++m]=i;
}
for(int j=1;j<=m;++j)
{
if (prime[j]*i>n||prime[j]>minp[i]) break;
minp[i*prime[j]]=prime[j];
}
}
return ;
}
int main()
{
scanf("%lld",&n);
make();
for(int i=1;i<=m;++i)
{
int nn=n;
while (nn)
{
cnt[i]+=nn/prime[i];
nn/=prime[i];
}
}
for(int i=1;i<=m;++i)
printf("%d %d\n",prime[i],cnt[i]);
return 0;
}