质数问题
质数常用性质
两个连续的自然数一定是互质数。如:4和5、13和14是互质数。
相邻的两个奇数一定是互质数。如:5和7、75和77是互质数。
两个数中的较大一个是质数,这两个数一定是互质数。如:3和19、16和97是互质数。
两个数中的较小一个是质数,而较大数是合数且不是较小数的倍数,这两个数一定是互质数。如:2和15、7和54是互质数。
较大数比较小数的2倍多1或少1,这两个数一定是互质数。如:13和27、13和25是互质数。
两个数分别除以它们的最大公约数,所得的商一定互质。
两个数的最小公倍数分别除以这两个数,所得的商一定互质。
两个互质的数a和b最小不能表示的数就是(a-1)(b-1)-1,也就是说两个互质的数a,b可以表示(a-1)(b-1)之后的所有数字。
中间是偶数的连续三个自然数互质。
6倍高效判断素数法
除了2和3外,其余素数都与6的倍数相邻,这些素数都满足6n±1。
这是个trivial的素数分布特征,因模6的余数中只有1和5与6互素,故从5开始的素数必与6的倍数相邻。
//从5开始,如果能整除6n+-1,肯定是合数
bool isprime(int num){
if(num==2||num==3){return true;}
if(num%6!=1&&num%6!=5){return false;}
int len=(int)sqrt(num);
for(int i=5;i<=len;i+=6){
if(num%i==0||num%(i+2)==0)
return false;
}
return true;
}
区间[1,n]埃式筛法
时间复杂度:O(nlogn)
[证明]
调和级数
vector<int> get_primes(int n) {
vector<int> res(n + 1, 1);
res[0] = res[1] = 0;
int len = sqrt(n);
for (int i = 2; i <= len; i++) {
if (res[i]) {
for (int j = i * i; j <= n; j += i) {
res[j] = 0;
}
}
return res;
}
区间[1,n]线性筛
时间复杂度:O(n)
//return:范围[1,n]的素数个数
const int N=1e8+10;
int pr[N],cnt;
bool vis[N];
int init(int n){
int res=0;
for(int i = 2; i<=n; i++){
if(!vis[i]) pr[cnt++] = i,res++;
for(int j = 0; j <cnt&&(1ll)*pr[j]*i<=n; j++){
vis[pr[j] * i] = true;
if(i % pr[j] == 0) break;//确保每个数被自己的最小质数筛掉
}
}
return res;
}
区间[l,r]质数判断
const int N=50010;
int l,r,cnt;
int pr[N],ispr[N];
void init(){
ispr[1]=1;
for(int i=2;i<N;i++){
if(!ispr[i]){
pr[++cnt]=i;
}
for(int j=1;j<=cnt&&i*pr[j]<N;j++){
ispr[i*pr[j]]=1;
if(i%pr[j]==0) break;//确保每个数被自己的最小质数筛掉
}
}
}
int ans[1000010],res=0;
void solve(){
cin>>l>>r;
init();
for(int i=1;i<cnt&&pr[i]<=r;i++){
for(ll j=max(2,(l+pr[i]-1)/pr[i]);j*pr[i]<=(ll)r;j++){
ans[j*pr[i]-l]=1;
}
}
if(l<=1) ans[1-l]=1;
for(int i=0;i<=r-l;i++){
if(!ans[i]) res++;
}
cout<<res;
}