筛法的思想是去除要求范围内所有的合数,剩下的就是素数了,而任何合数都可以表示为素数的乘积,则一个数的倍数为合数。
long long su[MAX],cnt;
bool isprime[MAX];
void prime()
{
cnt=1;
memset(isprime,1,sizeof(isprime));//初始化认为所有数都为素数
isprime[0]=isprime[1]=0;//0和1不是素数
for(long long i=2;i<=MAX;i++){
if(isprime[i]) su[cnt++]=i;
for(long long j=i*2;j<=MAX;j+=i)
isprime[j]=0;
}
}
合数的倍数一定会在筛素数倍数时候被筛掉,所以只筛素数就好,只把质数的倍速筛掉,就是找到一个质数,把它的倍数全部标记为合数。但是你会发现有的数字会被标记多次,比如12被2,3都标记,这样会浪费时间。
const int N=1e7+1;
int prime[N],b[N];
int cnt=0,max1;1e7;
int init()
{
memset(b,1,sizeof(b));
b[0]=b[1]=0;
for(int i=2;i<=max1;i++)
if(b[i]){
prime[++cnt]=i;
for(int j=2;j*i<=max1;j++)
b[i*j]=0;
}
return 0;
}
埃氏筛可以优化,普通的线性筛法虽然大大缩短了求素数的时间, 但是实际上还是做了许多重复运算,比如2*3=6,在素数2的时候筛选了一遍, 在素数为3时又筛选了一遍。如果只筛选小于等于素数i的素数与i的乘积, 既不会造成重复筛选,又不会遗漏。时间复杂度几乎是线性的。
我们要筛1-n中的素数,然后先默认他们都是素数,最外层枚举 1-n的所有数,
如果它是素数,就加到素数表,
对于每一个枚举的i ,枚举素数表里的数,然后素数就会标记自己 i 倍的数不是素数,(素数的倍数不是素数)
枚举素数表什么时候停?枚举到 i 的最小质因子,标记完就可以停了,保证每个数只被他的最小质因子筛掉。
例如:外层 i=15 时,素数表里:2,3,5,7,11,13
215=30,把30筛掉;315=45,把45筛掉,因为15%3==0,退出里面的循环;
15是被3筛掉的,因为3是15的最小素因子。
const int N=1e7+1;
int prime[N],b[N];
int cnt=0,max1;1e7;
int init()
{
memset(b,1,sizeof(b));
b[0]=b[1]=0;
for(int i=2;i<=max1;i++){
if(b[i]) prime[++cnt]=i;
for(int j=1;j<=cnt&&prime[j]*i<=max1;j++){
b[prime[j]*i]=0;
if(i%prime[j]==0) break;
}
}
}
int su(long long n)//0为素数,1不为素数
{
int flag=0;
for(int i=1;prime[i]<=sqrt(n*1.0);i++)
if(n%prime[i]==0) {
flag=1;break;}
if(n==1) flag=1;
return flag;
}
概念:任意一个大于0的正整数都能被表示成若干个素数的乘积且表示方法是唯一的; 整理可以将相同素数的合并;可以得到 公式
n = P1 ^ a1 · P2 ^ a2 · ………… · Pn ^ an(P1 < P2 < ……Pn)
void getprimefactor(long long n)
{
int cas=0;
for(int i=0;prime[i]*prime[i]<=n;i++){
while(!(n%prime[i])){
factor[cas]++;
n/=prime[i];
}
if(factor[cas]) cas++;
}
if(n>1) factor[cas]=1;
}
Description
李华再次发现有一种素数很奇特,它依次去掉最高位,剩下的仍为素数,例如:1223,3137等数。后来李华查阅资料知道这样的数叫纯素数。
现在给你一个整数能判断它是不是纯素数呢?
Input
测试数据有多组(不超过1e5组),每组只有一个整数N(1<=N<=1e6)
Output
对于每组数据,若N为纯素数,输出YES,否则输出NO
Sample Input
2
107
13903
Sample Output
YES
YES
NO
#include
using namespace std;
const int N=1e6+1;
int prime[N];
int b[N];
int cnt=0,max1=1e6;
int init()
{
memset(b,1,sizeof(b));
b[0]=b[1]=0;
for(int i=2;i<=max1;i++)
if(b[i]){
prime[++cnt]=i;
for(int j=2;i*j<=max1;j++)
b[i*j]=0;
}
}
int f(int n)
{
char a[10];
int j=0;
while(n){
a[j++]=n%10;
n/=10;
}
for(int i=0;i<j;i++){
//要一位一位的判断
int sum=0;
for(int j=i;j>=0;j--)
sum=sum*10+a[j];
if(!b[sum]) return 0;
}
return 1;
}
int main()
{
init(); //不要忘记在主函数打表
int n;
while(~scanf("%d",&n)){
if(f(n)) cout<<"YES\n";
else cout<<"NO\n";
}
return 0;
}
Description
给定一个范围 n,有 q 个询问,每次输出第 k 小的素数。(2<=n<=4e7,1<=q<=1e4)
Input
第一行包含两个正整数 n,q,分别表示查询的范围和查询的个数。
接下来 q 行每行一个正整数 k,表示查询第 k 小的素数。
Output
输出 q 行,每行一个正整数表示答案。
Sample Input
100 5
1
2
3
4
5
Sample Output
2
3
5
7
11
Hint
本题卡内存,注意内存! 用bool 类型来定义素数标记
#include
using namespace std;
const int N=4e7+1;
int prime[3000000];
bool b[40000001];
int cnt=0,max1=4e7;
int init() //线性筛模板
{
memset(b,1,sizeof(b));
b[0]=b[1]=0;
for(int i=2;i<=max1;i++){
if(b[i]) prime[++cnt]=i;
for(int j=1;j<=cnt&&prime[j]*i<=max1;j++){
b[prime[j]*i]=0;
if(!(i%prime[j])) break;
}
}
return 0;
}
int main()
{
ios::sync_with_stdio(0);
init();
int n,q,k;
cin>>n>>q;
while(q--){
cin>>k;
cout<<prime[k]<<endl;
}
return 0;
}
Description
求一个数的因子和。
Input
输入一个正整数T(T<=10000),表示有T组数据,每组数据包括一个整数n(1<=n<=1e12)
Output
输出这个数的因子和
Sample Input
1
2
Sample Output
3
#include
using namespace std;
typedef long long ll;
ll n;
ll oh() //可参考唯一分解定理的模板
{
ll ans=1;
for(ll i=2;i*i<=n;i++){
if(!(n%i)){
ll jet=1,sum=1;
while(!(n%i))
{
jet*=i;sum+=jet;n/=i;}
ans*=sum;
}
}
if(n>1) ans*=(n+1);
return ans;
}
int main()
{
ios::sync_with_stdio(0);
int t;
ll ans;
while(cin>>t)
while(t--){
cin>>n;
ans=oh();
cout<<ans<<endl;
}
return 0;
}