欧拉筛打印素数ADT,OJ156

核心代码:

if(i%prime[j]==0)break;

意思:当$i$是某个素数的整数倍时,$i*prime[j+1]$肯定被筛选过了,跳出循环。

关键:保证每个合数只会被它的最小质因数筛去

因为i当$i%prime[j]==0$时,$i$可以看作$prime[j]*某个数$,所以对于下个loop的$j$(我们用的$j+1$),可以写成$prime[j]*某个数*prime[j+1]$,而$prime[j]$一定小于$prime[j+1]$,所以在找到这一步时,一定已经被筛选过了。因为我们是用每个数的最小质因子进行筛选的。同时在这个筛选里我们可以发现性质:$prime[j]$一定是$i*prime[j]$的最小质因子。

156代码:这题一直爆WA是因为我觉得质数没有质因数。。。然而这题有。。。

//
//  main.cpp
//  156
//
//  Created by Yanbin GONG on 6/4/2018.
//  Copyright © 2018 Yanbin GONG. All rights reserved.
//

#include <iostream>
#include <stdio.h>
#include <iomanip>
#include <string>
#include <string.h>
#include <cmath>
#include <algorithm>

using namespace std;

const int maxn = 1000050;

int a,b;
int prime[maxn]; //打表
bool isPrime[maxn]; //保证不是素数的倍数
//线性时间

//欧拉筛法
void setPrime(int n){
    memset(isPrime,true,sizeof(isPrime));
    memset(prime,0,sizeof(prime));
    int num=0;
    for(int i=2;i<=n;i++){
        if(isPrime[i]==true){
            num++;
            prime[num] = i;//找到素数
        }
        //利用找到的素数把后面的合数筛选掉
        for(int j=1;((j<=num)&&(i*prime[j]<=n));j++){
            isPrime[i*prime[j]]=false;
            
            if(i%prime[j]==0)break;
            //这行代码保证了每个合数只会被它的最小素因子筛掉,把复杂度降到了O(N)
        }
    }
}

long long int key(int n){
    
    long long int max=0; //记录最大质因数
    long long int sum=0;
    int i;
    for(i=1;prime[i]<=n;i++){
        if(n%prime[i]==0){
            sum+=prime[i];
            max=prime[i];
        }
        while(n%prime[i]==0){
            n /= prime[i];
        }
    }
    return max*2-sum;
}

void ans(){
    long long int ka = key(a);
    long long int kb = key(b);
    //printf("ka=%d kb=%d
",ka,kb);
    if(ka>kb){
        cout<<"a
";
    }
    else{
        cout<<"b
";
    }
}

int main(){
    setPrime(maxn);
    while(scanf("%d%d",&a,&b)!=EOF){
        if(a==0&&b==0){
            break;
        }
        ans();
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/cmbyn/p/8727757.html