质数与约数
质数与约数:
整除与约数
设
质数与合数的定义:
对于
质数判定:
试除法:
单次时间复杂度
代码
bool is_prime(int n) {
if(n < 2)
return false;
for(int i=2; i<= sqrt(n); ++i) {
if(n % i == 0)
return false;
}
return true;
}
质数筛法一:
从
时间复杂度
代码
void found_prime() {
memset(vis, 0, sizeof(vis));
vis[0] = 1; vis[1] = 1; // 特殊处理 0 和 1
for(int i=2; i<=n; ++i) {
for(int j=i*2; j<=n; j+=i)
vis[j] = 1; // 标记合数
}
}
埃氏筛:
只需要枚举质数的倍数就可以标记到所有合数了。实际上对于每个质数
从
时间复杂度
代码
void found_prime() {
memset(vis, 0, sizeof(vis));
vis[0] = 1; vis[1] = 1; // 特殊处理 0 和 1
for(int i=2; i<=n; ++i) {
if(!vis[i]) { // i 为质数
for(int j=i*i; j<=n; j+=i)
vis[j] = 1; // 标记合数
}
}
}
线性筛:
用每一个合数的最小质因子来标记这个合数。时间复杂度
代码
int pr[N],cnt;
bool vis[N];
void init(){
int n=1e5+50;
for(int i=2;i<=n;i++){
if(!vis[i]){pr[++cnt]=i;}
for(int j=1;j<=cnt&&i*pr[j]<=n;j++){
vis[i*pr[j]]=1;
if(i%pr[j]==0)break;
}
}
}
区间筛:(埃氏筛)
代码
const int maxn = 1e6+10;
typedef long long LL;
bool is_prime[maxn]; //标记a~b范围内的质数
bool is_prime_small[maxn]; //标记 1~sqrt(n)范围内的所有质数
LL a, b;
//对区间[a, b]内的整数执行筛法,is_prime[i-a]=true表示i是素数
void found_prime()
{
for(LL i=0; i*i<=b; ++i)
is_prime_small[i] = true;
is_prime_small[1] = false;
for(LL i=0; i<=b-a; ++i)
is_prime[i] = true;
for(LL i=2; i*i<=b; ++i) {
if(is_prime_small[i]) { // i是质数
for(LL j=i*i; j*j<=b; j+=i) // 标记 sqrt(b) 以内的i的倍数
is_prime_small[j] = false;
for(LL j = max(2LL, (a+i-1)/i) * i; j<=b; j+=i) //标记[a, b]中i的倍数
is_prime[j-a] = false;
}
}
}
算术基本定理:
任何一个大于 1 的正整数都能唯一分解为若干个质数的乘积。
设
其中
根据算术基本的定理,对于任意一个大于
推论一:
推论二:
阶乘分解:
对于一个数
考虑对于一个质数
求 中包含多少个
答案是
对于每一个质数都用如上方式
共有个数,每次处理 的复杂度,总复杂度 。
求解正约数集合:
试除法 求
时间复杂度
代码
int divisor[10010], cnt = 0;
for(int i=1; i<=sqrt(n); ++i) {
if(n % i == 0) {
divisor[++cnt] = i;
if(i != n/i) divisor[++cnt] = n/i;
}
}
推论:一个整数
倍数法 求
先枚举
代码
vecotr<int> divisor[500010];
for(int i=1; i<=n; ++i) { // 先枚举约数 i
for(int j=1; j<=n/i; ++j) //枚举 i 在 1~n 范围内的倍数 i × j
divisor[i*j].push_back(i); // i 是 i × j 的约数
}
推论:
约数研究:
设
可以枚举每一个
, 中含有 个约数 。所以答案为
:
性质:
- 对于
若 则称 互质。 - 由于任何正整数都是
和 的公约数,故 不存在。 - 对于
,有 。 ,有 。
更相减损术:
,有 ,则 ,所以 也是 的公约数,所以 。
辗转相除法:
- 若
,则 - 若
,设 ,其中 。 。有 ,则 ,因此 ,也是 的公约数,故
代码:
代码
int gcd(int a, int b) {
while(b > 0 ) {
int x = a % b;
a = b;
b = x;
}
return a;
}
递归:
代码
int gcd(int a, int b) {
return b ? gcd(b, a%b) : a;
}
最大复杂度
:
实际代码中:
gcd与lcm:
给出某两个整数
设,从 来枚举 ,当 时停止枚举。
答案即为
CF1152C:
给定两个正整数
设
显然
由辗转相除法可知
所以
所以可以枚举的因子 ,若 则 ,否则
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!