Advertisement

2022.6.2 质数(素数)与合数

阅读量:

一、定义:

  1. 素数(p \neq 0, 1, -1):当且仅当整数p除了平凡因数(即(1, p))外没有其他因数时,则称p为素数值(不可分解元素)。

2.合数(a\neq 0,1,-1):a不是素数,则称a为合数。

二、性质:
1、如果a为合数,则必可以拆分为a=b*c(a>1 , a>b,c> 1)。

2、如果质数p有大于1的因数d,则p一定等于d。

3、大于1的合数a一定可以拆分为多个质数的乘积。

4、大于1的合数a必有质数p导致批 p | a(\sqrt{a}\geq p)。

5、质数有无穷多个。

6、大于4的质数都可以分解成6n\pm 1的形式。

复制代码
 证明:

    
 一个数k(大于3)%6可能会有余数:0,1,2,3,4,5
    
 余数0,2,4 则k必为偶数
    
 余数为3 3+6n=3+3*2n=3*(2n+1),为合数
    
 只剩余数1,5 为 6n+1 和 6n-1

三、质数计数函数: {\color{Red} \pi (n)}

表示小于或等于n的素数的个数。

四、质数判定:

1、暴力枚举:

复制代码
 bool isPrime(int n){

    
 	if(n<2)return false;
    
 	for(int i=2;i<n;i++){
    
 		if(n%i==0)return false;
    
 	}
    
 	return true;
    
 }

时间复杂度O(n),容易超时。

当一个正整数的最小质因数为2时,则其最大因数值不会超过n的一半。

复制代码
 bool isPrime(int n){

    
 	if(n<2)return false;
    
 	for(int i=2;i<=n/2;i++){
    
 		if(n%i==0)return false;
    
 	}
    
 	return true;
    
 }

3、简单检测:

这样做是十分稳妥了,但不一定所有数都要判断。

很容易发现这样一个事实:如果a是n的约数,那么\sqrt{a}也是n的约数。

这一结论表明,在任意两个正整数的情况下,请考虑其中较小的那个数值。为了解决问题方便起见,请关注所有这些较小的数值是否都落在区间 [1, \sqrt{a}] 内。

由于1肯定是约数,所以不检验它。

复制代码
 bool isPrime(int n){

    
 	if(n<2)return false;
    
 	for(int i=2;i*i<=n;i++){
    
 		if(n%i==0)return false;
    
 	}
    
 	return true;
    
 }

五、筛数:
1、埃氏筛)

不是质数的数不筛 2 3 4 5 6 7 8 9 10
2 |0 1 0 1 0 1 0 1
3 ||0 0 1 0 0 1 0
4 |||||||||
5 ||||0 0 0 0 1
6 |||||||||
7 ||||||0 0 0
8 |||||||||
9 |||||||||
结果 质数 质数 合数 质数 合数 质数 合数 合数 合数

先用2去筛,即把2留下,把2的倍数剔除掉

再用下一个质数,也就是3筛,把3留下,把3的倍数剔除掉;

接下去用下一个质数5筛,把5留下,把5的倍数剔除掉;

不断重复下去…

复制代码
 void ass(int n){

    
 	bool vis[n+1];
    
 	int prime[n+1],len=0;
    
 	for(int i=2;i<=n;i++){
    
 		if(!vis[i]){
    
 			prime[++len]=i;
    
 			for(int j=2;i*j<=n;j++){
    
 				vis[i*j]=1;
    
 			}
    
 		}
    
 	}
    
 }

2、欧拉筛:
在埃氏筛的运算中,10被算了两次,特别浪费。

复制代码
 void ols(int n){

    
 	int a[n+1],b[n+1];
    
 	for(int i=2;i<=n;i++){
    
 		if(a[i]==0){
    
 			b[++k]=i;
    
 		}
    
 		for(int j=1;i*j<=n;j++){
    
 			if(i*b[j]>n)break;
    
 			a[i*b[j]]=1;
    
 			if(i%b[j]==0)break;
    
 		}	
    
 	}
    
 }

六、真题演练:洛谷(P2441 角色属性树)

题目描述:

这个"绪萌同人社"组织具有一定的趣味性。从组织架构来看,则呈现出一种典型的树状结构:此类型下的领导层配置中包含一个主要负责人,在其手下配置若干副总负责人;在这一层级中,则会依次配置若干部门负责人……

每一个角色都具有独特的萌点属性,在这个属性中包含一组质数作为基础元素,并以乘积形式存在(比如猫耳数值为2、弱气数值为3、黄毛数值为5、病娇数值为7、双马尾数值为11以此类推)。

举个例子,正妹是双份的猫耳,而且有一份弱气,她的属性值为223=12。

当前团队成员对某一问题尤为关注,并希望找到与自己最接近且具有相同萌属性的上司。举个例子来说,在实际操作中我们通常将属性值如2、4、6及45等视为具备相同的属性特征。

然而,组员可能会随时变化自己的属性。啊。。感觉好麻烦啊。。

输入格式:

第一行,n,k 表示成员数与询问的次数

第二行,n个数,分别是1~n号成员的属性值

接下来n-1行,x_i,y_i 表示x_i是y_i的上司。

接下来来k行,有两种情况

1 u_i 询问离u_i成员最近且有相同萌元素上司。

2 u_i a 更改u_i的属性值为a

输出格式:

对于每一个类型为1的查询,请返回满足条件的所有结果编号;若无满足条件的结果,请返回-1号结果

输入样例:

复制代码
 4 6

    
 10 8 4 3
    
 1 2
    
 2 3
    
 3 4
    
 1 1
    
 1 2
    
 1 3
    
 1 4
    
 2 1 9
    
 1 4

输出样例:

复制代码
 -1

    
 1
    
 2
    
 -1
    
 1

说明提示:

对于20%的数据,没有修改的操作。

对于50%的数据,n<=100,修改次数<10

对于100%的数据,n<=200000,k<100000 ,修改次数<=50,a_i<=2^31-1

UPD:本题测试数据随机,可能是假题。

思路:

使用vector建一棵树,记录上司是谁。再用暴力dfs搜索。

实现:

复制代码
 #include <iostream>

    
 #include <algorithm>
    
 #include <iomanip>
    
 #include <cstring>
    
 #include <fstream>
    
 #include <sstream>
    
 #include <vector>
    
 #include <string>
    
 #include <cstdio>
    
 #include <cmath>
    
 #include <deque>
    
 #include <queue>
    
 #include <stack>
    
 #include <list>
    
 #include <map>
    
 using namespace std;
    
 const int N = 2e5 + 10;
    
 const int INF = 0x3f3f3f3f;
    
 int n,k,a[N],x,y,op; 
    
 vector<int>v[N];
    
 int gcd(int a,int b){
    
 	if(a<b){
    
 		swap(a,b);
    
 	}
    
 	if(a%b==0)return b;
    
 	if(a==1||b==1)return 1;
    
 	return gcd(b,a%b);
    
 }
    
 int dfs(int u,int pos){
    
 	int len=v[u].size();
    
 	if(len<1){
    
 		return -1;
    
 	}else{
    
 		for(int i=0;i<len;i++){
    
 			if(gcd(a[v[u][i]],a[pos])>1){
    
 				return v[u][i];
    
 			}
    
 		}
    
 		for(int i=0;i<len;i++){
    
 			return dfs(v[u][i],pos);
    
 		}
    
 	}
    
 }
    
 int main(){
    
 	cin >>n>>k;
    
 	for(int i=1;i<=n;i++){
    
 		cin >>a[i];
    
 	}
    
 	for(int i=1;i<=n-1;i++){
    
 		cin >>x>>y;
    
 		v[y].push_back(x);
    
 	}
    
 	for(int i=1;i<=k;i++){
    
 		cin >>op;
    
 		if(op==1){
    
 			cin >>x;
    
 			cout <<dfs(x,x)<<endl;
    
 		}else{
    
 			cin >>x>>y;
    
 			a[x]=y;
    
 		}
    
 	}
    
 	return 0;
    
 }

全部评论 (0)

还没有任何评论哟~