【质数】

【质数】

判定质数:试除法

时间复杂度 O(sqrt(n))

思路

image

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t,a;
bool is_prime(int n){
	if(n<2) return false;
	//注意这里细节:尽量不要写成i<=sqrt(n) 或者 i*i<=n 
	for(int i=2;i<=n/i;i++){
		if(n%i==0) return false;
	}
	return true;
}
signed main(){
      ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
      cin>>t;
      while(t--){
      	cin>>a;
      	if(is_prime(a)) cout<<"Yes"<<"\n";
      	else cout<<"No"<<"\n";
	}
      return 0;
}

分解质因数:试除法

时间复杂度 最好O(logn) 最坏O(sqrt(n))

思路

(1)从小到大枚举所有数
(2)n中最多只包含一个大于sqrt(n)的质因子
->先枚举小于sqrt(n)的 再单独输出一次

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t,a;
void divide(int n){
	for(int i=2;i<=n/i;i++){
		//细节:这里不需要特别去判质数
		/*
		先除的2 那么就把2的倍数全部除掉了
		先除的3 那么就把3的倍数全部除掉了
		以此类推 
		*/ 
		if(n%i==0){
			//判次数
			int s=0;
			while(n%i==0){
				n/=i;//直接更新n 
				s++;
			}
			cout<<i<<" "<<s<<"\n";
		}
	}
	//单独输出一次大于sqrt(n)的质数(注意特判n>1防止n被除完而输出1) 
	if(n>1) cout<<n<<" 1"<<"\n";
	cout<<"\n";
}
signed main(){
      ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
      cin>>t;
      while(t--){
      	cin>>a;
      	divide(a);
	}
      return 0;
}

筛质数:埃式筛法(埃筛)

思路

(1)朴素算法:从小到大把该数的倍数删掉 O(nlogn)
(2)优化:只需要删质数的倍数 O(nloglogn)->O(n)

质数定理

image

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1000010;
int t; 
int primes[N],cnt;
bool st[N];
void get_primes(int n){
	for(int i=2;i<=n;i++){
		if(st[i]) continue;//只需要筛质数 
		primes[cnt++]=i;//记录质数 
		for(int j=i+i;j<=n;j+=i){//把倍数全部删掉 
			st[j]=true;
		}
	}
}
signed main(){
      ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
      cin>>t;
      get_primes(t);
      cout<<cnt;
      return 0;
}

筛质数:线性筛法(欧拉筛)

更快

思路

O(n)
1.对于每个数n,只会被它的最小质因子筛掉
分类讨论:
(1)i%primes[j]==0
     primes[j]一定是i的最小质因子
     primes[j]一定是primes[j]*i的最小质因子
(2)i%primes[j]!=0
     primes[j]一定小于i的所有质因子(要继续找更大的质因子)
     primes[j]也一定是primes[j]*i的最小质因子
->不管什么情况 primes[j]一定是primes[j]*i的最小质因子->primes[j]*i被筛掉
2.对于一个合数x,一定有一个最小质因子
  当i枚举到i/primes[j]时 x就会被筛掉

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1000010;
int t; 
int primes[N],cnt;
bool st[N];
void get_primes(int n){
	for(int i=2;i<=n;i++){
		if(!st[i]) primes[cnt++]=i;//是质数 
		//小细节:不用写j<=cnt -> 一定会在小于cnt时停下 
		//primes[j]<=n/i -> 把大于n的合数筛去没意义 
		for(int j=0;primes[j]<=n/i;j++){//找每一个质因子 
			st[primes[j]*i]=true;//最小质因子的倍数都是合数->筛去 
			if(i%primes[j]==0) break;//primes[j]一定小于i的所有质因子(要继续找更大的质因子)
		}
	}
}
signed main(){
      ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
      cin>>t;
      get_primes(t);
      cout<<cnt;
      return 0;
}

题目积累

质数筛法

LCM Sequence(区间筛素数)

用埃筛写

https://atcoder.jp/contests/abc412/tasks/abc412_e

区间筛素数做法
设区间为L,R
(1)如果一个数x不是质数:至少在sqrt(x)范围内有1个因子
->先把sqrt(R)内的所有质数筛出(线性筛法即可)
(2)遍历质数表:对于一个质数pr
找(L+pr-1)/pr*pr到R/pr*pr的所有pr倍数 并筛去
(3)没被筛到的数就是质数
题目大意

image
image

思路
【思路】能让lcm变化仅有两种方式:
(1)该数为质数
->素数筛的区间筛法:
判断1e14内的一个数不是质数:一定有一个sqrt(1e14)=1e7内的因数
->把1e7内的质数全部筛去->用埃筛的方式筛去所有合数

image

(2)质数的幂次:质因子只有1个
->想到2^64也才循环64次->暴力求解即可
代码
const int N=1e7+10;
i64 l,r;
bool vis[N];
void solve(){
    cin>>l>>r;
	if(l==r){
		cout<<1<<endl;
		return;
	}
	get_primes(N);
    for(int i=0;i<primes_cnt;i++){
		if(primes[i]>r) break;
		//(1)
		i64 x=(l+primes[i]-1LL)/primes[i]*primes[i];
		i64 y=r/primes[i]*primes[i];
		for(i64 k=x;k<=y;k+=primes[i]){
			vis[k-l]=1;
		}
	}
	for(int i=0;i<primes_cnt;i++){
		if(primes[i]>r) break;
		//(2)
		i64 pr=primes[i];
		while(pr<=r){
			if(pr>l) vis[pr-l]=0;//注意这里不是>=l:第一个数不用累计
			pr*=primes[i];
		}
	}
	int sz=r-l+1;
	int ans=1;
	for(int i=1;i<sz;i++) if(!vis[i]) ans++;//注意第一个数不累计->从l+1开始
	cout<<ans<<endl;
}
posted @ 2025-01-19 00:36  White_ink  阅读(38)  评论(0)    收藏  举报