试除法求约数 O ( n ) O(\sqrt{n}) O(n)
需要注意的是如果一个数是平方数的话需要特判一下只加一个进去
模板题:AcWing 869. 试除法求约数
核心代码如下:
for(int i = 1; i <= a / i; ++i)
{
if(a % i == 0)
{
ans.push_back(i);
if(i != a / i)
ans.push_back(a / i);
}
}
约数个数
N
=
p
1
a
1
∗
p
2
a
2
∗
p
3
a
3
⋅
⋅
⋅
p
n
a
n
,
其
中
p
是
质
因
子
N=p_1^{a_1}*p_2^{a_2}*p_3^{a_3}···p_n^{a_n},其中p是质因子
N=p1a1∗p2a2∗p3a3⋅⋅⋅pnan,其中p是质因子
那么约数个数
c
n
t
=
(
a
1
+
1
)
(
a
2
+
1
)
(
a
3
+
1
)
⋅
⋅
⋅
(
a
n
+
1
)
cnt=(a_1+1)(a_2+1)(a_3+1)···(a_n+1)
cnt=(a1+1)(a2+1)(a3+1)⋅⋅⋅(an+1)
模板题:AcWing 870. 约数个数
模板代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int mod = 1e9 + 7;
int n, a;
int main()
{
map<int, int> m;
scanf("%d", &n);
while(n--)
{
scanf("%d", &a);
for(int i = 2; i <= a / i; ++i)
{
if(a % i == 0)
{
while(a % i == 0)
{
++m[i];
a /= i;
}
}
}
if(a>1)//记得这里还要考虑如果还有一个比较大的质因数
++m[a];
}
ll res = 1;
for(auto it: m)
res = res * (1 + it.second) % mod;
printf("%lld", res);
return 0;
}
约数之和
N
=
p
1
a
1
∗
p
2
a
2
∗
p
3
a
3
⋅
⋅
⋅
p
n
a
n
,
其
中
p
是
质
因
子
N=p_1^{a_1}*p_2^{a_2}*p_3^{a_3}···p_n^{a_n},其中p是质因子
N=p1a1∗p2a2∗p3a3⋅⋅⋅pnan,其中p是质因子
N
N
N 的所有约数之和
s
u
m
=
(
p
1
0
+
p
1
1
+
p
1
2
+
⋅
⋅
⋅
+
p
1
a
1
)
(
p
2
0
+
p
2
1
+
p
2
2
+
⋅
⋅
⋅
+
p
2
a
2
)
⋅
⋅
⋅
(
p
n
0
+
p
n
1
+
p
n
2
+
⋅
⋅
⋅
+
p
n
a
n
)
sum=(p_1^0+p_1^1+p_1^2+···+p_1^{a_1})(p_2^0+p_2^1+p_2^2+···+p_2^{a_2})···(p_n^0+p_n^1+p_n^2+···+p_n^{a_n})
sum=(p10+p11+p12+⋅⋅⋅+p1a1)(p20+p21+p22+⋅⋅⋅+p2a2)⋅⋅⋅(pn0+pn1+pn2+⋅⋅⋅+pnan)
模板题:AcWing 871. 约数之和
下面这是个运算技巧
w
h
i
l
e
(
a
−
−
)
while(a--)
while(a−−)
t
=
(
t
∗
b
+
1
)
%
m
o
d
;
t=(t*b+1)\%mod;
t=(t∗b+1)%mod;
AC代码如下:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mod=1e9+7;
int n,a;
int main()
{
scanf("%d",&n);
map<int,int>m;
while(n--)
{
scanf("%d",&a);
for(int i=2;i<=a/i;++i)
if(a%i==0)
{
while(a%i==0)
{
++m[i];
a/=i;
}
}
if(a>1)
++m[a];
}
ll res=1;
for(auto x:m)
{
int b=x.first,a=x.second;
ll t=1;
while(a--)
t=(t*b+1)%mod;
res=res*t%mod;
}
printf("%lld",res);
return 0;
}
用递归来求如下:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int mod = 1e9 + 7;
int n, a;
ll qmi(ll p, int k)
{
p %= mod;
ll ans = 1;
while(k)
{
if(k & 1)
ans = ans * p % mod;
p = p * p % mod;
k >>= 1;
}
return ans;
}
ll sum(int p, int k)
{
if(k == 0)
return 1;
if(k & 1)//如果是奇数次幂
return ((1 + qmi(p, k / 2 + 1)) * sum(p, k / 2)) % mod;
else//如果是偶数次幂
return (p % mod * sum(p, k - 1) + 1) % mod;
}
int main()
{
map<int, int> m;
scanf("%d", &n);
while(n--)
{
scanf("%d", &a);
for(int i = 2; i <= a / i; ++i)
{
if(a % i == 0)
{
while(a % i == 0)
{
++m[i];
a /= i;
}
}
}
if(a > 1)
++m[a];
}
ll res = 1;
for(auto it: m)
res = sum(it.first, it.second) * res % mod;
printf("%lld", res);
return 0;
}
最大公约数
欧几里得算法==辗转相除法
如果
d
∣
a
d \,|\, a
d∣a,并且
d
∣
b
d\,|\, b
d∣b,那么有
d
∣
a
x
+
b
y
d\,|\,ax\,+\,by\,
d∣ax+by
所以
(
a
,
b
)
=
(
b
,
a
m
o
d
b
)
(a,b)=(b,a \,mod \,b)
(a,b)=(b,amodb)
理由如下:
(
b
,
a
m
o
d
b
)
(b,a \,mod \,b)
(b,amodb)等价于
(
b
,
a
−
c
∗
b
)
(b,a-c*b)
(b,a−c∗b),
c
c
c 是一个整数
(
a
,
b
)
(a,b)
(a,b)与
(
b
,
a
−
c
∗
b
)
(b,a-c*b)
(b,a−c∗b)可以由倍数互相转换
模板题:AcWing 872. 最大公约数
核心代码如下:
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;//gcd()经过变换之后里面一定是左大右小
}