1 月 30 日算法练习-数论

唯一分解定理

唯一分解定理指的是:对于任意一个>1的正整数,都可以以唯一的一种方式分解为若干质因数的乘积。
x = p 1 k 1 ⋅ p 2 k 2 ⋅ … ⋅ p m k m x = p_1^{k_1} \cdot p_2^{k_2} \cdot \ldots \cdot p_m^{k_m} x=p1k1p2k2pmkm
这个式子中的p1,p2是类似2,3,5,7这样的质数。
将单个数字进行质因数方法是,从小到大枚举x的所有可能的质因子,最大枚举到sqrt(x),每遇到一个可以整除的数字i,就不断进行除法直到除尽。最后如果还有x>1,说明还有一个较大的质因子。

#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 9;
vector<pair<int, int>> v;

int main() {
    int x;
    cin >> x;

    // Enumerate all possible prime factors
    for (int i = 2; i <= x / i; ++i) {
        // If it doesn't divide, skip
        if (x % i) continue;

        // If it divides, it must be a prime factor (due to the nature of enumeration from small to large)
        // Count represents the exponent of the current prime factor (i)
        int cnt = 0;

        // Keep dividing until it is no longer divisible
        while (x % i == 0) {
            cnt++;
            x /= i;
        }

        v.push_back({i, cnt});
    }

    // If x is greater than 1, it means x itself is a prime factor
    if (x > 1) {
        v.push_back({x, 1});
    }

    // Print the prime factors and their exponents
    for (const auto &i : v) {
        cout << i.first << ' ' << i.second << '\n';
    }

    return 0;
}

约数个数定理

通过某个数字的唯一分解: x = p 1 k 1 ⋅ p 2 k 2 ⋅ … ⋅ p m k m x = p_1^{k_1} \cdot p_2^{k_2} \cdot \ldots \cdot p_m^{k_m} x=p1k1p2k2pmkm
我们可以求出x的约数(因数)个数,如果学过线性代数或者有向量相关的知识的话,可以理解为将不同的质因子看作是不同的向量空间或基底,不同质因子之间互不干扰。
也就是说p1的指数的取值是[0,k1]共(k1+1)个,p2,p3…亦然,所以x的约数的个数就是 (k1+1)*(k2+1)*…*(km+1),即: d ( x ) = ∏ i = 1 m ( k i + 1 ) d(x) = \prod_{i=1}^{m}(k_i + 1) d(x)=i=1m(ki+1)

阶乘约数在这里插入图片描述

思路:100!阶乘太大,不能直接求出再求正约数。可以用唯一分解定理和约数个数定理来求约数个数。

#include<iostream>
using namespace std;
const int N = 1e2 + 5;
int a[N];

void f(int x){
    
    for(int i=2;i<=x/i;i++){
        if(x%i)continue;
        int cnt = 0;
        while(x%i==0){
            cnt++;
            x/=i;
        }
        a[i]+=cnt;
    }
    if(x>1)a[x]++;
}

int main(){
    for(int i = 1;i<=100;i++)f(i);
    
    long long ans =1;
    
    for(int i=1;i<=100;i++)ans*=(a[i]+1);
    
    cout<<ans<<'\n';
    return 0;
}

在这里插入图片描述

求值

在这里插入图片描述

#include<iostream>
using namespace std;

int check(int x) {
    int cnt = 0;
    for(int i=1;i*i<=x;i++){
        if(x%i==0){
            if(i==x/i)cnt++;
            else cnt+=2;
        }
    }
    return cnt == 100;
}

int main() {
    for(int i=1; ;i++){
        if(check(i)){
            cout<<i<<'\n';
            break;
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小蒋的学习笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值