线性筛法
#include <bits/stdc++.h>
using namespace std;
const int N=1e7;
bool flag[N+10];
int prime[N+10];
int main()
{
memset(flag,1,sizeof(flag));
flag[0]=0;flag[1]=0;
int index=0;
for(int i=2;i<=N;i++)
{
if(flag[i])prime[index++]=i;
for(int j=0;j<index&&prime[j]*i<=N;j++)
{
flag[prime[j]*i]=0;
if(i%prime[j]==0)break;
}
}
return 0;
}
复杂度为O(n),得到素数集合prime[],flag[i]判断i是不是素数,也可以让flag[i]=index+1,flag的值就保存了i是第几个素数
这题好难哦,解题思路:唯一分解定理:举个例子:18的因子和
素因子为332,因子和为(3^2 + 3^1 + 3^0) * (2^1 +2^0)=39
所以可以用一个二维数组(或者结构体)把素因子及其幂存起来,最后用等比数列求和公式a1*(q^n-1)/(q-1),a1都是1
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int prime[78500];
bool f[1000000];
const int N=1e6;
void data()
{
int cnt=0;
memset(f,1,sizeof(f));
for(int i=2;i<N;i++)
{
if(f[i])prime[cnt++]=i;
for(int j=0;j<cnt&&prime[j]*i<N;j++)
{
f[i*prime[j]]=0;
if(i%prime[j]==0)break;
}
}
}
ll quick(ll a,int n)
{
ll ans=1;
while(n)
{
if(n&1)ans=ans*a;
n>>=1;
a=a*a;
}
return ans;
}
int main()
{
data();
int t,n;
scanf("%d",&t);
while(t--)
{
int a[20][2],cnt=0,i=0;
scanf("%d",&n);
while(n!=1&&i<=3401)
{
if(n%prime[i]==0)
{
a[cnt][1]=0;
while(n%prime[i]==0)
{
n/=prime[i];
a[cnt][1]++;
}
a[cnt++][0]=prime[i];
}
i++;
}
if(n!=1)
{
a[cnt][1]=1;
a[cnt++][0]=n;
}
ll ans=1;
for(int i=0;i<cnt;i++)
{
ans*=(quick((ll)a[i][0],a[i][1]+1)-1)/(a[i][0]-1);
}
printf("%lld\n",ans);
}
return 0;
}
变化不大,简单题
#include <bits/stdc++.h>
using namespace std;
const int N=1e7;
bool flag[N+10];
int prime[N+10];
int main()
{
memset(flag,1,sizeof(flag));
int index=0;
flag[1]=0;
flag[0]=0;
for(int i=2;i<=N;i++)
{
if(flag[i])prime[index++]=i;
for(int j=0;j<index&&prime[j]*i<=N;j++)
{
flag[prime[j]*i]=0;
if(i%prime[j]==0)break;
}
}
int n;
while(~scanf("%d",&n))
{
if(flag[n])printf("YES\n");
else printf("NO\n");
}
return 0;
}
也变化不大,依次去掉最高位,判断是不是素数
#include <bits/stdc++.h>
using namespace std;
int a[1000005],b[1000005];
int main()
{
int n,m,cnt;
memset(a,1,sizeof(a));
for(int i=2;i<=1000000;i++)
{
if(a[i]!=0)
for(int j=2;i*j<=1000000;j++)a[i*j]=0;
}
cnt=0;
for(int i=2;i<=1000000;i++)
{
if(a[i]!=0)b[++cnt]=i;
}
while(cin>>n)
{
int sum=0;
if(n==1){cout<<"0"<<endl;continue;}
for(int i=cnt;i>=1;i--)
{
if(n%b[i]==0){cout<<i<<endl;break;}
}
}
return 0;
}
发现组数多的时候,cin和cout都挺占时间的,一开始用cout都tle了
#include <bits/stdc++.h>
using namespace std;
const int N=1e6;
bool flag[N+10];
int prime[N+10];
int main()
{
int n;
memset(flag,1,sizeof(flag));
int index=0;
for(int i=2;i<N;i++)
{
if(flag[i])prime[index++]=i;
for(int j=0;j<index&&prime[j]*i<N;j++)
{
flag[prime[j]*i]=0;
if(i%prime[j]==0)break;
}
}
flag[0]=0,flag[1]=0;
while(~scanf("%d",&n))
{
if(!flag[n]){printf("NO\n");continue;}
int A=1e5;
int flag0=1;
for(int i=0;;i++)
{
n=n%A;
if(!flag[n]){flag0=0;break;}
A=A/10;
if(n<10)break;
}
if(flag0==1)printf("YES\n");
else printf("NO\n");
}
return 0;
}
}
这题卡时间,思路:两个素数相乘小于N,用数组标记,一重循环小于sqrt(N),可以避免重复,减少时间
#include <bits/stdc++.h>
using namespace std;
const int N=1e6;
int flag[N+10];
int prime[N+10];
int flag0[N];
int main()
{
memset(flag,1,sizeof(flag));
int index=0;
for(int i=2;i<N;i++)
{
if(flag[i]){prime[index++]=i;flag[i]=index;}
for(int j=0;j<index&&prime[j]*i<N;j++)
{
flag[prime[j]*i]=0;
if(i%prime[j]==0)break;
}
}
flag[1]=0;
int n;
for(int i=0;prime[i]<sqrt(N*1.0);i++)
{
for(int j=i;prime[j]*prime[i]<N;j++)
{
flag0[prime[j]*prime[i]]=1;
}
}
while(~scanf("%d",&n))
{
if(flag0[n])printf("YES\n");
else printf("NO\n");
}
return 0;
}
用到一个小技巧flag[n]本来是用来判断是否是素数的,可以让flag也存上这个素数是第几个素数,然后找x开始为素数的下标与y+1开始的下标,相减就是之间的素数个数
#include <bits/stdc++.h>
using namespace std;
const int N=2e6;
int flag[N+10];
int prime[N+10];
int main()
{
memset(flag,1,sizeof(flag));
int index=0;
for(int i=2;i<N;i++)
{
if(flag[i]){prime[index++]=i;flag[i]=index;}
for(int j=0;j<index&&prime[j]*i<N;j++)
{
flag[prime[j]*i]=0;
if(i%prime[j]==0)break;
}
}
flag[1]=0;
int x,y,sum;
while(~scanf("%d %d",&x,&y))
{
sum=0;
int i,j;
for(i=x;;i++)
{
if(flag[i]){i=flag[i];break;}
}
for(j=y+1;;j++)if(flag[j]){j=flag[j];break;}
sum=j-i;
cout<<sum<<endl;
}
return 0;
}
判断1e14大小的素数的方法:用线性筛求出1e7以内的素数再判断这个数能否被前面的素数整除,不能则是素数
#include <bits/stdc++.h>
using namespace std;
const int N=1e7;
bool flag[N+10];
int prime[N+10];
int su(long long n)
{
int flag=0;
for(int i=0;prime[i]<=sqrt(1.0*n);i++)
{
if(n%prime[i]==0){flag=1;break;}
}
if(n==1)flag=1;
return flag;
}
int main()
{
memset(flag,1,sizeof(flag));
int index=0;
for(int i=2;i<N;i++)
{
if(flag[i])prime[index++]=i;
for(int j=0;j<index&&prime[j]*i<N;j++)
{
flag[prime[j]*i]=0;
if(i%prime[j]==0)break;
}
}
int n;
scanf("%d",&n);
long long a,b,c,sum;
while(n--)
{
scanf("%lld %lld %lld",&a,&b,&c);
sum=a+b-c;
if(su(sum)==0)printf("yes\n");
else printf("no\n");
}
return 0;
}
这题非常简单就是套模板就行
#include <bits/stdc++.h>
using namespace std;
const int N=1e7;
bool flag[N+10];
int prime[N+10];
int main()
{
memset(flag,1,sizeof(flag));
int index=0;
for(int i=2;i<N;i++)
{
if(flag[i])prime[index++]=i;
for(int j=0;j<index&&prime[j]*i<N;j++)
{
flag[prime[j]*i]=0;
if(i%prime[j]==0)break;
}
}
int n,q;
scanf("%d %d",&n,&q);
int a;
while(q--)
{
scanf("%d",&a);
printf("%d\n",prime[a-1]);
}
return 0;
}