约数

约数

试除法求约数

Code

//获取一个数的所有约数,从小到大 
vector<int> get_divisors(int n) {
	vector<int> res;
	for(int i = 1; i <= n / i; i++) { //最多只要枚举到sqrt(n) 
		if(n % i == 0) {
			res.push_back(i);
			if(i != n / i) res.push_back(n / i); //把它成对的约数push进vector 
		}
	}
	sort(res.begin(), res.end());

	return res;
}

求一个数所有约数的个数

N = p 1 α 1 p 2 α 2 . . . p n α n N=p_1^{\alpha_1}p_2^{\alpha_2}...p_n^{\alpha_n} N=p1α1p2α2...pnαn ,其中, p p p N N N 的质因数, α i \alpha_i αi 是约数的指数,则一个数所有约数的个数为

a n s = ( a 1 + 1 ) ( a 2 + 1 ) ( a 3 + 1 ) . . . ( a n + 1 ) ans=(a_1+1)(a_2+1)(a_3+1)...(a_n+1) ans=(a1+1)(a2+1)(a3+1)...(an+1)

理由是,任何一个约数 d d d 可以表示成 p β 1 p β 2 p β 3 . . . p β n   , 0 ≤ β i ≤ α i p^{β_1}p^{β_2}p^{β_3}...p^{β_n}\ ,0≤β_i≤α_i pβ1pβ2pβ3...pβn ,0βiαi ,每一项的 β i \beta_i βi 如果不同,那么约数 d d d 就不相同(算数基本定理,每个数的因式分解是唯一的)所以, n n n 的约数就跟 β i β_i βi 的选法是一一对应的 β 1 β_1 β1 一共有 0 ∼ α 1 0∼α_1 0α1 种选法, β 2 β_2 β2 一共有 0 ∼ α 2 0∼α_2 0α2 种选法 → \to β k β_k βk 一共有 0 ∼ α k 0∼α_k 0αk 种选法,根据乘法原理,一共有 a n s ans ans 个约数

一个小结论: i n t int int 范围内,约数最多的一个数的约数大概是1500个

Code

ll divnum(ll x) {
	unordered_map<ll, ll> primes;
	for(int i = 2; i <= x / i; i++) {
		while(x % i == 0) {
			x /= i;
			primes[i]++;
		}
	}
	if(x > 1) primes[x]++;
	ll res = 1;
	for(auto prime : primes) res = res * (prime.second + 1);
	
	return res;
}

练习

C. Common Divisors

约数之和

N = p 1 α 1 p 2 α 2 . . . p n α n N=p_1^{\alpha_1}p_2^{\alpha_2}...p_n^{\alpha_n} N=p1α1p2α2...pnαn ,其中, p p p N N N 的质因数, α i \alpha_i αi 是约数的指数,则一个数的所有约数之和为

a n s = ( p 1 0 + p 1 1 + p 1 2 + . . . p 1 α 1 ) × ( p 2 0 + p 2 1 + p 2 2 + . . . p 2 α 2 ) × ( p 3 0 + p 3 1 + p 3 2 + . . . p 3 α 3 ) × . . . × ( p k 0 + p k 1 + p k 2 + . . . p k α k ) ans=(p_1^{0}+p_1^{1}+p_1^{2}+...p_1^{\alpha_1})\times(p_2^{0}+p_2^{1}+p_2^{2}+...p_2^{\alpha_2})\times (p_3^{0}+p_3^{1}+p_3^{2}+...p_3^{\alpha_3})\times...\times(p_k^{0}+p_k^{1}+p_k^{2}+...p_k^{\alpha_k}) ans=(p10+p11+p12+...p1α1)×(p20+p21+p22+...p2α2)×(p30+p31+p32+...p3α3)×...×(pk0+pk1+pk2+...pkαk)

使用乘法分配率展开,每一项都是约数

如何计算每一个项呢

while(a--) t = (t * p + 1) % mod;

通过对计算步骤的复现可以知道

当执行 1 次时, t = ( p + 1 ) t=(p+1) t=(p+1)

当执行 2 次时, t = ( p + 1 ) × p + 1 = p 2 + p + 1 t=(p+1)\times p +1=p^2+p+1 t=(p+1)×p+1=p2+p+1

当执行 3 次时, t = p 2 + p + 1 × p + 1 = p 3 + p 2 + p + 1 t=p^2+p+1\times p+1=p^3+p^2+p+1 t=p2+p+1×p+1=p3+p2+p+1

这样可以知道,执行 α k \alpha_k αk 次之后,得到的式子就是

t = p 1 0 + p 1 1 + p 1 2 + . . . p 1 α 1 t=p_1^{0}+p_1^{1}+p_1^{2}+...p_1^{\alpha_1} t=p10+p11+p12+...p1α1

Code

给定 n n n 个正整数 a i a_i ai ,请你输出这些数的乘积的约数之和,答案对 1 0 9 + 7 10^9+7 109+7 取模。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const long long mod = 1e9 + 7;

int main() {
    int T;
    scanf("%d", &T);
    unordered_map<int, int> primes;//存储分解完成的质数
    while(T--) {
        int x;
        scanf("%d", &x);
        //分解每个质数
        for(int i = 2; i <= x / i; i++) {
            while(x % i == 0) {
                x /= i;
                primes[i]++;
            }
        }
        if(x > 1) primes[x]++;
    }

    ll res = 1;
    for(auto prime : primes) {
        int p = prime.first, a = prime.second; //p表示约数 a表示约数的指数
        ll t = 1;
        while(a--) t = (t * p + 1) % mod;//根据公式计算每一项
        res = res * t % mod;
    }

    printf("%lld\n", res);

    return 0;
}

求最大公约数

使用

__gcd(a,b);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值