数学知识—约数

20240627 数学知识一 40:32

  1. 类似质数 试除法

    869 求约数
    只要枚举到n/i就够了!!!!
    时间复杂度 O根号n big o notation

    排序52:00
    lnlnn比根号n小 忽略不计 了

    数论题关键算时间复杂度,每一步都算才不会超时!!!

#include<iostream>
	#include<vector>
	#include<algorithm>
	
	using namespace std;
	
	vector<int> get_divisors(int n ){
	    vector<int> res;
	    
	    // 约数 只用看到n/i就够了!!!
	    for(int i = 1; i <= n/i; i ++){
	        if(n %i == 0)
	        {
	            res.push_back(i);
	            // 边界处理,防止重复放 n/i =i
	            if(i != n/i) res.push_back(n/i);
	        }
	    }
	    sort(res.begin(), res.end());
	    return res;
	}
	
	int main(){
	    int n;
	    cin >> n;
	    while( n --){
	        int x;
	        cin >> x;
	        auto res= get_divisors(x);
	        for(auto t :res) cout << t<<" ";
	        puts("");
	    }
	    
	    return  0;
	}

记两个不同的公式

870 约数个数

基于算术基本定理
显然:因为排列组合,从α1个p1里选不同个数的p1有0-p1共1+p1种选法
所以约数个数是(α1+1)(α2+1) ……

概率论讲过
N的约数d可以写成:0<=β1<=α1

先分解质因数把a1 a2。。分别分解

map:存<指数的底数pi,质数的幂ai>,然后约数个数就是(幂a1+1)(幂a2+1)(幂+1)= Π(幂+1)

#include<iostream>
#include<algorithm>
#include<unordered_map> //hash表快一点 不map

using namespace std;

typedef long long LL;
const int mod = 1e9+7; //答案需对 109+7取模。

int main(){
    int n;
    cin >> n;
    
    unordered_map<int, int> primes;
    while( n--) {
        int x;
        cin >> x;
        
        // 枚举约数到x/i
        for(int i = 2; i <= x/i; i ++){
            while(x % i == 0){
                x /= i;
                primes[i] ++; //以这个质因数为底的幂 +1
            }
        }
        
        if( x> 1) primes[x] ++; //x是一个比较大的质因数 为啥
        
    }
    
    LL res = 1;
    for(auto prime: primes) res= res*(prime.second +1) % mod;
    cout << res;
    return 0;
}

871 约数之和
类似上面,只不过把约束和表示出来,然后暴力展开
乘积总个数=上面约数个数

如何求t=p0+…pa 不需要用快速幂再加速了(有logα算法分治)
总和 求p^0+ … + p^a;做a次的p*t +1妙啊

Auto+map好用!!

#include<iostream>
#include<algorithm>
#include<unordered_map> //hash表快一点 不map

using namespace std;

typedef long long LL;
const int mod = 1e9+7; //答案需对 109+7取模。

int main(){
    int n;
    cin >> n;
    
    unordered_map<int, int> primes;
    while( n--) {
        int x;
        cin >> x;
        
        // 枚举约数到x/i
        for(int i = 2; i <= x/i; i ++){
            while(x % i == 0){
                x /= i;
                primes[i] ++; //以这个质因数为底的幂 +1
            }
        }
        
        if( x> 1) primes[x] ++; //x是一个比较大的质因数 为啥
        
    }
    
    LL res = 1;
    
    // 870比只改了这里
    for(auto prime: primes) 
    {
        int p = prime.first, a= prime.second;//p底,a指数
        LL t= 1; //总和 求p^0+ ... + p^a;做a次的p*t +1妙啊
        while(a  --) t= (t*p+1) %mod;
        res = res * t % mod;
        
    }
    cout << res;
    return 0;
}

最大公约数——欧几里得算法——辗转相除法 01:19:23

时间复杂度Logn不用更相减损术

性质:
1. 如果d能整除a(就是a % d =0)而且d整除b,那么d能整除a,b线性组合ax+by
2. (a,b)=(b, a % b) a和b的最大公约数= b和a模b 的最大公约数
因为a % b= a- (a|b) *b (a模b= a - (a整除b)*b= a -c * b)
所以证明 (a,b) = (b, a-c * b) c=a|b

设a,b公约数是d
那么左边得 d|a且d|b,又因为性质一所以 d| ax +by 这里x=1, y=-c
所以b和a-c*b公约数是d

反过来右边推出 d|b且d|a-cb
所以d|bx+(a-c
b)y,此时y=1,x=c,能推出d|a
所以a b公约数也是d

所以左右所有的公约数集合都相同,所以左边的最大公约数也是右边的 证毕

模板:

#include<iostream>

using namespace std;

// 很常用
int gcd(int a, int b){
    // 如果b=0,返回(b, a%b)的公约数
    // 否则b=0, (a,0)=返回a 不能是0
    return b ? gcd(b, a%b): a;
}

int main(){
    int n;
    scanf("%d", &n);
    
    while(n --){
        int a, b;
        scanf("%d%d", &a, &b);
        printf("%d\n", gcd(a, b));
    }
    return 0;
}

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值