当前位置:网站首页>质数相关问题-小记
质数相关问题-小记
2022-08-02 14:10:00 【老顽固也可爱】
质数相关问题
质数又名素数,在ACM中经常出现相关问题,例如 P1029 NOIP2001 普及组 最大公约数和最小公倍数问题、P2043 质因子分解、P3383 【模板】线性筛素数 等等,今天就先来讲讲这几题目的共性。
奇技淫巧-欧几里得算法
欧几里得算法又称辗转相除法,是指用于计算两个非负整数a,b的最大公约数。应用领域有数学和计算机两个方面。计算公式 g c d ( a , b ) = g c d ( b , a m o d b ) gcd(a,b) = gcd(b,a mod b) gcd(a,b)=gcd(b,amodb) 。
inline int gcd(int x,int y)
{
if(y==0) return x;
return gcd(y,x%y);
}
例题如下:
[NOIP2001 普及组] 最大公约数和最小公倍数问题
题目描述
输入两个正整数 x 0 , y 0 x_0, y_0 x0,y0,求出满足下列条件的 P , Q P, Q P,Q 的个数:
P , Q P,Q P,Q 是正整数。
要求 P , Q P, Q P,Q 以 x 0 x_0 x0 为最大公约数,以 y 0 y_0 y0 为最小公倍数。
试求:满足条件的所有可能的 P , Q P, Q P,Q 的个数。
输入格式
一行两个正整数 x 0 , y 0 x_0, y_0 x0,y0。
输出格式
一行一个数,表示求出满足条件的 P , Q P, Q P,Q 的个数。
样例 #1
样例输入 #1
3 60
样例输出 #1
4
提示
P , Q P,Q P,Q 有 4 4 4 种:
- 3 , 60 3, 60 3,60。
- 15 , 12 15, 12 15,12。
- 12 , 15 12, 15 12,15。
- 60 , 3 60, 3 60,3。
对于 100 % 100\% 100% 的数据, 2 ≤ x 0 , y 0 ≤ 10 5 2 \le x_0, y_0 \le {10}^5 2≤x0,y0≤105。
【题目来源】
NOIP 2001 普及组第二题
题解
首先你需要先理解最大公约数和最小公倍数是怎么计算的。
要是 a a a 和 b b b 的 最大公约数为 m m m、最小公倍数为 n n n,则可以推断出 a ∗ b / m = n a*b/m=n a∗b/m=n ,而且 a / m a/m a/m 和 b / m b/m b/m 的 最大公约数是 1 1 1 。至于为什么?emmm,数学的直觉就是这样子的。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int sd(int a,int b)
{
if(a%b==0)
{
return b;
}
else
{
return sd(b,a%b);
}
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
if(m%n!=0)
{
printf("0\n");
continue;
}
int k=m/n;
int sum=0;
for(int i=1;i<sqrt(k);i++)
{
if(k%i==0)
{
int q=k/i;
if(sd(q,i)==1)
{
sum++;
}
}
}
printf("%d\n",sum*2);
}
return 0;
}
质因子分解
题目描述
对N!进行质因子分解。
输入格式
输入数据仅有一行包含一个正整数N,N<=10000。
输出格式
输出数据包含若干行,每行两个正整数p,a,中间用一个空格隔开。表示N!包含a个质因子p,要求按p的值从小到大输出。
样例 #1
样例输入 #1
10
样例输出 #1
2 8
3 4
5 2
7 1
提示
10!=3628800=(28)*(34)*(5^2)*7
题解
这题就要用到质数的定义了,首先可以知道 一个数分解到最后一定是一堆质数的乘积。
那么假设这个数是 n n n ,就只要从 2 2 2 开始一直到 n n n 分解这个数,不用判断是不是质数,因为每个质因子我们都一直除,直到不能再除,以后也不会出现可以除的数是此数的倍数了,相当于已经筛掉了,所以最后一定会被分解成质数的乘积。
#include<iostream>
using namespace std;
int a[10001]={
0},n; //数组很大,记得开在外面哦
int main()
{
cin>>n;
for (int i=2;i<=n;i++) //1就不用了,从2到n一个一个来
{
int i2=i; //备份一下,不然等会被除掉了
for (int j=2;j<=i;j++) //从2开始判断是否可以整除
while (i2%j==0) {
a[j]++; i2/=j;}
//记得使用while,不是if,要一除到底
}
for (int i=1;i<=10000;i++) //输出
if (a[i]!=0)
cout<<i<<" "<<a[i]<<endl;
}
判断质数方法-总结
一个比较普通的判定方法
bool IsPrime()
{
for(int i=2;i<=sqrt(n);i++)
{
if(n%i==0) return false;
}
return true;
}
Eratosthenes筛选法(质数的倍数一定不是质数)
同时对于每个x,把大于等于x的平方的x的倍数标记为合数。
void isprime(int n)///筛选1-n的素数
{
memset(vis,0,sizeof(vis));
int m = sqrt(n + 0.5);
for(int i = 2; i <= m; i++)
{
if(!vis[i])
{
for(int j = i * i; j <= n; j += i)
vis[j] = 1;
}
}
}
线性筛法
每个合数只会被它的最小质因子筛一次,时间复杂度 O ( n ) O(n) O(n)
int v[maxn],prime[maxn];
void primes(int n)
{
memset(v,0,sizeof(v));///最小质因子
m=0;
for(i=2;i<=n;i++)
{
if(v[i]==0)///i为质数
{
v[i]=i;
prime[++m]=i;
}
///给当前的数i乘上一个质因子
for(j=1;j<=m;j++)
{
///i有比prime[i]更小的质因子,或者超出n的范围
if(prime[j]>v[i]||prime[j]>n/i) break;
v[i*prime[j]]=prime[j];
}
}
for(i=1;i<=m;i++)
cout<<prime[i]<<endl;
}
最快模板
还有一个在网上看到的一个判断素数的方法,这是当时ccpc的时候也用到过的一个模板。
bool isPrime( int num )
{
//两个较小数另外处理
if(num ==2|| num==3 )
return 1 ;
//不在6的倍数两侧的一定不是质数
if(num %6!= 1&&num %6!= 5)
return 0 ;
int tmp =sqrt( num);
//在6的倍数两侧的也可能不是质数
for(int i= 5;i <=tmp; i+=6 )
if(num %i== 0||num %(i+ 2)==0 )
return 0 ;
//排除所有,剩余的是质数
return 1 ;
}
这个算是我看到的判断素数最快的一种方法了
质数筛
对于一些求解第几个质数的问题,可以先打表,然后直接输出,这样会快一点。但是这种做法的时间一般大都都在之前的打表上,怎么减少打表的时间成了重中之重。下面这道题就是在解决这个问题。
【模板】线性筛素数
题目背景
本题已更新,从判断素数改为了查询第 k k k 小的素数
提示:如果你使用 cin
来读入,建议使用 std::ios::sync_with_stdio(0)
来加速。
题目描述
如题,给定一个范围 n n n,有 q q q 个询问,每次输出第 k k k 小的素数。
输入格式
第一行包含两个正整数 n , q n,q n,q,分别表示查询的范围和查询的个数。
接下来 q q q 行每行一个正整数 k k k,表示查询第 k k k 小的素数。
输出格式
输出 q q q 行,每行一个正整数表示答案。
样例 #1
样例输入 #1
100 5
1
2
3
4
5
样例输出 #1
2
3
5
7
11
提示
【数据范围】
对于 100 % 100\% 100% 的数据, n = 1 0 8 n = 10^8 n=108, 1 ≤ q ≤ 1 0 6 1 \le q \le 10^6 1≤q≤106,保证查询的素数不大于 n n n。
Data by NaCly_Fish.
#include <cstdio>
#include <cstring>
bool isPrime[100000010];
//isPrime[i] == 1表示:i是素数
int Prime[6000010], cnt = 0;
//Prime存质数
void GetPrime(int n)//筛到n
{
memset(isPrime, 1, sizeof(isPrime));
//以“每个数都是素数”为初始状态,逐个删去
isPrime[1] = 0;//1不是素数
for(int i = 2; i <= n; i++)
{
if(isPrime[i])//没筛掉
Prime[++cnt] = i; //i成为下一个素数
for(int j = 1; j <= cnt && i*Prime[j] <= n/*不超上限*/; j++)
{
//从Prime[1],即最小质数2开始,逐个枚举已知的质数,并期望Prime[j]是(i*Prime[j])的最小质因数
//当然,i肯定比Prime[j]大,因为Prime[j]是在i之前得出的
isPrime[i*Prime[j]] = 0;
if(i % Prime[j] == 0)//i中也含有Prime[j]这个因子
break; //重要步骤。见原理
}
}
}
int main()
{
int n, q;
scanf("%d %d", &n, &q);
GetPrime(n);
while (q--)
{
int k;
scanf("%d", &k);
printf("%d\n", Prime[k]);
}
return 0;
}
边栏推荐
- PHY6222蓝牙5.2支持MESH组网M0内核超低功耗
- FP6296锂电池升压 5V9V12V内置 MOS 大功率方案原理图
- How to set the win10 taskbar does not merge icons
- cmake configure libtorch error Failed to compute shorthash for libnvrtc.so
- DP4056电源保护芯片锂电池pin对pinTP4056
- FP6293电池升压5V-12V大电流2APWM模式升压方案
- FP7126降压恒流65536级高辉无频闪调光共阳极舞台灯RGB驱动方案
- FP5139电池与适配器供电DC-DC隔离升降压电路反激电路电荷泵电路原理图
- Summarize computer network super comprehensive test questions
- Mysql之MVCC
猜你喜欢
Win10上帝模式干嘛的?Win10怎么开启上帝模式?
Win7 encounters an error and cannot boot into the desktop normally, how to solve it?
【系统设计与实现】基于flink的分心驾驶预测与数据分析系统
How to update Win11 sound card driver?Win11 sound card driver update method
深入理解Golang之Map
What is Win10 God Mode for?How to enable God Mode in Windows 10?
Mysql连接错误解决
In-depth understanding of Golang's Map
FP6296锂电池升压 5V9V12V内置 MOS 大功率方案原理图
Use tencent cloud builds a personal blog
随机推荐
基于最小二乘法的线性回归分析方程中系数的估计
What should I do if Windows 10 cannot connect to the printer?Solutions for not using the printer
推开机电的大门《电路》(二):功率计算与判断
Yolov5 official code reading - prior to transmission
Daily - Notes
DP1332E内置c8051的mcu内核NFC刷卡芯片国产兼容NXP
Summarize computer network super comprehensive test questions
7. How to add the Click to RecyclerView and LongClick events
General syntax and usage instructions of SQL (picture and text)
推开机电的大门《电路》(三):说说不一样的电阻与电导
How to set the win10 taskbar does not merge icons
CI24R1小模块2.4G收发模块无线通信低成本兼容si24r1/XN297超低功耗
设备驱动框架简介
倍增和稀疏表
Mysql连接错误解决
jest test, component test
小T成长记-网络篇-1-什么是网络?
专硕与学硕
Do Windows 10 computers need antivirus software installed?
用U盘怎么重装Win7系统?如何使用u盘重装系统win7?