数学知识—约数

20240627 数学知识一 40:32

  1. 类似质数 试除法

    869 求约数

    只要枚举到n/i就够了!!!!

    时间复杂度 O根号n big o notation

    排序52:00

    lnlnn比根号n小 忽略不计 了

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

cpp 复制代码
#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)

cpp 复制代码
#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=p^0+...p^a 不需要用快速幂再加速了(有logα算法分治)

总和 求p^0+ ... + p^a;做a次的p*t +1妙啊

Auto+map好用!!

cpp 复制代码
#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

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

模板:

cpp 复制代码
#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;
}
相关推荐
xiaoshiguang33 小时前
LeetCode:222.完全二叉树节点的数量
算法·leetcode
爱吃西瓜的小菜鸡3 小时前
【C语言】判断回文
c语言·学习·算法
别NULL3 小时前
机试题——疯长的草
数据结构·c++·算法
TT哇3 小时前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯
CYBEREXP20084 小时前
MacOS M3源代码编译Qt6.8.1
c++·qt·macos
ZSYP-S4 小时前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
yuanbenshidiaos4 小时前
c++------------------函数
开发语言·c++
yuanbenshidiaos4 小时前
C++----------函数的调用机制
java·c++·算法
唐叔在学习4 小时前
【唐叔学算法】第21天:超越比较-计数排序、桶排序与基数排序的Java实践及性能剖析
数据结构·算法·排序算法
ALISHENGYA5 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法