20240626
课程链接地址
数学知识一
数论——质数
866 质数判定
法一:
暴力法试除法
法二:
优化, d|n d整除n, 那么n/d一定能整除n
比如n=12, d=3可以, n/d= 4 也可以整除12
所以枚举较小的d 那么n/d一定是,不用枚举了 到n/i!!!
所以本来枚举n次, 现在根号n次
但是不推荐
写 I * I <= n 因为当i接近intmax,会i*i溢出,会变成一个负数 可以用Longlong也行
或者 I <= sqrt(n) 因为sqrt太慢了
写成 I <= n/I
#include<iostream>
#include<algorithm>
using namespace std;
// 法一:纯暴力法O(n) 过不了 会超时
bool is_prime1(int n){
if(n < 2) return false;
for(int i =2; i <= n; i ++){
if( n % i == 0) return false;
}
return true;
}
// 法二: 根号n用n/i
bool is_prime2(int n){
if(n < 2) return false;
for(int i =2; i <= n / i ; i ++){
if( n % i == 0) return false;
}
return true;
}
int main(){
int n, a;
cin >> n;
while(n --){
cin >> a;
if(is_prime2(a)) printf("Yes\n");
else printf("No\n");
}
return 0;
}
分解质因数 08:21
- 从小到大枚举所有数 会不会有问题:因为所有数= 合数+质数 不会 因为当枚举到i,已经把2到i-1的所有质因子都除干净了 因为i之前都n%之前的 !=0 跳过了没计数, =0的都除过了,所以不会出现合数,一定是已经除干净了 此时如果还满足n%i=0,那么 i一定是质数
- 优化 降时间复杂度:n中至多包含一个大于根号n的质因子, 因为如果两个,那么俩乘一块,一定大于n i<=n/I 这里注意最后单独处理这个大于根号n的质因子
- 注意: 上一题优化以后一定是O(根号n) 但是这题不一定是根号n 比如n = 2^k, 枚举 i=2 一直除干净k次= log2_n到n= 1,结束了
所以时间复杂度介于O log2_n ~O 根号n
// 暴力法
void divide1(int n){
for(int i = 2; i <= n; i ++){
// 枚举所有数= 质数+合数,但是合数已经被跳过,不计数
// 已经是质数的都除干净了
if(n % i == 0) {
// 满足的i次数
int s = 0;
while (n % i == 0)
{
// 辗转相除
n /= i;
s ++;
}
printf("%d %d\n", i, s);
}
}
}
// 优化法
void divide2(int n){
for(int i = 2; i <= n/i; i ++){
if(n % i == 0) {
// 满足的i次数
int s = 0;
while (n % i == 0)
{
// 辗转相除
n /= i;
s ++;
}
printf("%d %d\n", i, s);
}
}
if(n > 1) printf("%d %d\n", n, 1);
puts("");
}
int main(){
int n, a;
cin >> n;
while(n --){
cin >> a;
divide2(a);
}
return 0;
}
筛 858 16:23 云里雾里的
20240627
-
删2所有倍数 依次往后删3 4 5 。。。的所有倍数
剩下所有数就是质数 p不是2- (p-1)任何一个数的倍数!!! -
删2 循环了 n/2次
删3 循环n/3次
求和调和级数!!高数忘了,c欧拉常数0.57796无限不循环常数 1/x求和lnx -
优化埃式筛法
不删所有数的倍数,只删质数的倍数
for放for里!!
因为不需要枚举判断2- p-1所有的数是不是p的约数
只要判断其中的质数是不是p的约数就行,减少计算判断质数定理:1-n有n/lnn个质数 所以粗略O(nlnn/lnn)= o(n) 其实是o(nlog2log2n) 但基本上是O(n)级别,比如2^32, log2=32, log2=5, 埃式筛法,希腊人埃拉托斯特尼发明的
-
优化2——线性筛法
每个合数只会被它最小质因子筛掉,从小到大枚举所有质数
用质数把合数筛掉时间快一倍
Pj =primes[j]
比如x=12, pj =2 枚举到x/pj= 6 已经筛过了,每个数只被筛一次,不会重复,所以线性!!for没有必要加j<cnt,只用primes[j] <=n/i就行了
听的乱七八糟云里雾里有点 数学知识题一定要会原理,自己推一遍
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1000010;
int primes[N], cnt = 0;
bool st[N];
void get_primes(int n){
for(int i = 2; i <= n; i ++){
if (!st[i]){
primes[cnt ++ ] = i;
}
for (int j = i + i; j <= n; j += i)
st[j] = true;
}
}
// 埃式筛法
void get_primes2(int n){
for(int i = 2; i <= n; i ++)
{
if (!st[i]){
primes[cnt ++ ] = i;
for (int j = i + i; j <= n; j += i)
st[j] = true;
}
}
}
// 线性筛法
void get_primes3(int n){
for(int i = 2; i <= n; i ++){
// 是质数就加
if(!st[i]) primes[cnt ++] = i;
// 从小到大 枚举当前所有质数,
for(int j = 0; primes[j] <= n/i; j ++){
st[primes[j] * i ] =true;
if( i % primes[j] == 0) break; // primes[j]一定是i的最小质因子
}
}
}
int main(){
int n;
cin >> n;
get_primes(n);
cout << cnt << endl;
return 0;
}