核心代码:
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; }