简单的数学知识

一些简单的数学知识

质数 约数

质数

质数即为因子只有自己和1的数,合数有多个因子包括且不限于自己和1

求质数的方法有很多

试除法

试除法是比较简单的一个方法

只需要循环从1到n之间的所有数字

时间复杂度为 O(n2)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<iostream>

using namespace std;

void solve()
{
int cot;
cin >> cot;
for(int i = 2;i < cot;i ++)
{
if(cot % i == 0)
{
puts("No");
return ;
}
}
puts("Yes");
}

int main()
{
int t = 1;
cin >> t;
while(t --)
{
solve();
}
return 0;
}
C++

埃氏筛

但是试除法很慢,所以需要一种的写法

对于一个数n来说,他的最大的因子是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<iostream>

using namespace std;

void solve()
{
int cot;
cin >> cot;
if(cot == 1)
{
puts("No");
return ;
}
for(int i = 2;i <= cot / i;i ++)
{
if(cot % i == 0)
{
puts("No");
return ;
}
}
puts("Yes");
}

int main()
{
int t = 1;
cin >> t;
while(t --)
{
solve();
}
return 0;
}
C++

欧氏筛

如果对于从1到n的质数,那么使用埃氏筛该如何写呢

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<iostream>

using namespace std;
const int N = 1e6 + 10;
int f[N];

void solve()
{
int n;
cin >> n;
for(int i = 2;i <= n;i ++)
{
for(int j = 2;j <= n / j;j ++)
{
f[i * j] = 1;
}
}
for(int i = 1; i <= n;i ++)
{
cout << f[i] << ' ';
}
}

int main()
{
solve();
return 0;
}
C++

但是这种写法有可能被一些数据卡掉,所以就需要线性筛即欧氏筛

为什么线性筛会比埃氏筛快呢,埃氏筛中在计算时进行了很多余的计算 例如 6 它会被 i = 2 和 i = 3 计算两次

线性筛会在出现这种情况的时候及时退出,不在计算节省了时间,线性筛使用了空间换时间优化了埃氏筛

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<iostream>

using namespace std;
const int N = 1e6 + 10;
int f[N], p[N], idx;

void solve()
{
int n;
cin >> n;
for(int i = 2;i <= n;i ++)
{
if(!f[i]) p[idx ++] = i;
for(int j = 0;j < idx && i * p[j] <= n;j ++)
{
if(i * p[j] <= n) f[i * p[j]] = 1;
if(i % p[j] == 0) break;
}
}
cout << idx << '\n';
}

int main()
{
solve();
return 0;
}
C++

约数

对于求每个数的约数,同样可以使用试除法来完成

那么有没有更快的方法呢

对于一个数n,它有一个因子为a,那么一定存在另一个因子b,得到 a * b = n

并且a和b的最大值为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<iostream>

using namespace std;

void solve()
{
int n;
cin >> n;
for(int i = 1;i <= n / i;i ++)
{
if(n % i == 0) cout << i << ' ' << n / i << ' ';
}
puts("");
}

int main()
{
int t = 1;
cin >> t;
while(t --)
solve();
return 0;
}
C++

约数个数的计算

给出n个数,求相乘之后的因子数量

对于他们的乘积all的因子有

对于每个因子都有对应的次方数,即每个因子可以选择对应的次方数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include<iostream>
#include<map>

const int mod = 1e9 + 7;

using namespace std;

void solve()
{
int n;
cin >> n;
map<int,int> ma;
for(int i = 0; i < n;i ++)
{
int cot;
cin >> cot;
for(int j = 2;j <= cot / j;j ++)
{
while(cot % j == 0)
{
ma[j] ++;
cot /= j;
}
}
if(cot > 1) ma[cot] ++;
}
int ans = 1;

for(auto &[u,v] : ma)
{
ans = 1ll * ans * (v + 1) % mod;
}
cout << ans << '\n';
}

int main()
{
solve();
return 0;
}
C++

约数之和的计算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include<iostream>
#include<map>

using namespace std;

const int mod = 1e9 + 7;

void solve()
{
int n;
cin >> n;

map<int,int> ma;

for(int i = 0;i < n;i ++)
{
int cot;
cin >> cot;
for(int j = 2;j <= cot / j;j ++)
{
while(cot % j == 0)
{
ma[j] ++;
cot /= j;
}
}
if(cot > 1) ma[cot] ++;
}

long long ans = 1;

for(auto &[u,v] : ma)
{
long long t = 1;
while(v --) t = (t * u + 1) % mod;
ans = (ans * t) % mod;
}
cout << ans << endl;
}
int main()
{
solve();
return 0;
}
C++

对于其乘积为all,

即其中所所有的因子的次方和相加再将所有的次方和相乘

$(p_1^1+p_1^2+p_1^3+…)(….)(p_n^1+p_n^2+p_n^3+…)$

每个相乘出来即可得到结果

欧几里得

有两个数 a 和 b,求出 a 和 b的最大公约数

辗转相除法可求得也叫欧几里得(gcd)

首先假设,即a和b的最大公因数是c

$$
ca_1 = ck*b_1 + t
$$

t从数值上可得为 a % b,且 即c为t的因子

可证得=>gcd(a,b) = gcd(b,a % b);

辗转相除即为a%b的相互模取

为什么是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<iostream>

using namespace std;

int gcd(int a, int b)
{
int r = a % b;
while(r)
{
a = b;
b = r;
r = a % b;
}
return b;
}

int main()
{
int n;
cin >> n;
while(n --)
{
int a, b;
cin >> a >> b;
cout << gcd(a,b) << '\n';
}
return 0;
}
C++

扩展欧几里得算法

扩展欧几里得可以求解,求出一个 x 和 y 的结果且x和y不为零

有裴蜀定理可得一定有解,且x和y不为零,当且仅当 $ax + by = 1$时,a和b互质

证明:如果a和b不为质数即,c为gcd(a,b),可得,当前仅当c为1时成立

扩展欧几里得推导

以gcd为基础

当递归到gcd中b为0时,有,此时可由gcd得知

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include<iostream>

using namespace std;

int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;

return d;
}

void solve()
{
int n;
cin >> n;
while(n --)
{
int a, b, x, y;
cin >> a >> b;
exgcd(a, b, x, y);
cout << x << ' ' << y << '\n';
}
}

int main()
{
solve();
return 0;
}
C++

费马小定理

给n对数字 a 和 p,p为质数

求解 a 模 p 的乘法逆元

=>

可通过费马小定理得出

证明费马小定理

对于一个质数,求解他的关于m的乘法逆元

=

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<iostream>

using namespace std;
#define ll long long

ll qpow(int a,int b,int p)
{
ll ans = 1;
while(b)
{
if(b&1) ans = ans * a % p;
a = 1ll * a * a % p;
b >>= 1;
}
return ans;
}

int main()
{
int n;
cin >> n;
while(n --)
{
int a, b;
cin >> a >> b;
if(a % b) cout << qpow(a, b - 2, b) << '\n';
else puts("impossible");
}
return 0;
}
C++

简单的数学知识
http://example.com/2024/03/26/数学类知识/
作者
smg
发布于
2024年3月26日
许可协议