约数相关习题+代码

约数

1.约数的定义

约数,又称因数。 整数 a a a 除以整数 b b b ( b ≠ 0 b \neq 0 b=0) 除得的商正好是整数而没有余数,即 b ∣ a b|a ba。我们就说 a a a 能被 b b b 整除,或 b b b 能整除 a a a a a a 称为 b b b 的倍数, b b b 称为 a a a 的约数。

2.习题

1.求一个数所有的约数

我们可以从枚举从 1 1 1 x \sqrt{x} x ,x能被i整除的话我们就可以获取两个约数。(需要注意当 i = x / i i = x/i i=x/i的特殊情况,这种情况,我们只需要记录一个约数

时间复杂度: O ( n ) O(\sqrt{n}) O(n )

C++代码:

vector<int> get(int x){
    vector<int> res;
    for(int i = 1;i <= x / i;i++){
        if(x % i==0){
            res.push_back(i);
            //如果 i != x/i,才添加第二个约数
            if(i != x/i) res.push_back(x/i);
        }
    }
    sort(res.begin(),res.end());
    return res;
}

java代码:

 public static List<Integer> get(int x){
        List<Integer> list = new ArrayList<>();
        for(int i = 1;i <= x/i;i++){
            if(x % i == 0){
                list.add(i);
                if(i != x/i) list.add(x/i);
            }
        }
        Collections.sort(list);
        return list;
    }

2.求约数的个数

唯一分解定理:任一大于 1 1 1 的自然数,要么本身是质数,要么可以分解为几个质数之积,且这种分解是唯一的。例如: 20 = 2 × 2 × 5 20 = 2 \times 2 \times 5 20=2×2×5 8 = 2 × 2 × 2 8 = 2 \times 2 \times 2 8=2×2×2

一个数 x x x 必然可以以这样的形式表示出来 x = p 1 a 1 × p 2 a 2 × … p n a n x = p_1^{a_1} \times p_2^{a_2} \times…p_n^{a_n} x=p1a1×p2a2×pnan p p p 是质因子, a a a是该质因子的个数)。例如: 36 = 2 2 × 3 2 36 = 2^2 \times 3^2 36=22×32

所以 x x x 的约数个数就可以得出为: ( a 1 + 1 ) × ( a 2 + 1 ) × . . . ( a n + 1 ) (a_1 + 1) \times (a_2 + 1) \times ...(a_n + 1) (a1+1)×(a2+1)×...an+1)。例如:若 c = a 2 × b 2 c = a^2 \times b^2 c=a2×b2,那么 c c c 的因子有( 1 , b , b 2 , a , a b , a b 2 , a 2 , a 2 b , a 2 b 2 1,b,b^2,a,ab,ab^2,a^2,a^2b,a^2b^2 1bb2aabab2a2a2ba2b2)共 9 9 9 个。

时间复杂度: O ( n × a ) O(n \times \sqrt{a}) O(n×a )

C++代码:

void divide(int x){
    //哈希表记录质因子 以及 它的个数
    unordered_map<int,int> cnt;
    int old = x;
    //分解质因数
    for(int i = 2;i <= x/i;i++){
        if(x % i==0){
            while(x % i == 0){
                cnt[i]++;
                x /= i;
            }
        }
    }
    if(x > 1) cnt[x]++;
    
    //计算约数个数
    int ans = 1;
    //枚举哈希表,k代表枚举到的质因子,v代表质因子k的个数
    for(auto &[k,v]:cnt){
        ans *= (v + 1); 
    }
    printf("%d 的约数个数为 %d\n",old,ans);
}

java代码:

public static void divide(int x){
        Map<Integer, Integer> map = new HashMap<>();
        int old = x;
        for(int i = 2;i <= x/i;i++){
            if(x % i == 0){
                while(x % i == 0){
                    map.put(i,map.getOrDefault(i,0)+1);
                    x /= i;
                }
            }
        }
        if(x > 1) map.put(x,1);

        int ans = 1;
        for(Integer key:map.keySet()){
            int v = map.get(key);
            ans *= (v + 1);
        }
        System.out.println(old +" 的约数个数为: "+ans);
    }

3.求约数之和

约数之和的公式为: s u m = ( p 1 0 + p 1 1 + . . . + p 1 a 1 ) × ( p 2 0 + p 2 1 + . . . + p 2 a 2 ) × . . . ( p n 0 + p n 1 + . . . + p n a n ) sum = (p_1^0 + p_1^1 + ...+p_1^{a_1}) \times (p_2^0 + p_2^1 + ...+p_2^{a_2}) \times ...(p_n^0 + p_n^1 + ... + p_n^{a_n}) sum=(p10+p11+...+p1a1)×(p20+p21+...+p2a2)×...(pn0+pn1+...+pnan)
例如: c = a 2 × b 2 c = a^2 \times b^2 c=a2×b2,那么 c c c 的约数有: ( 1 , b , b 2 , a , a b , a b 2 , a 2 , a 2 b , a 2 b 2 ) (1,b,b^2,a,ab,ab^2,a^2,a^2b,a^2b^2) (1bb2aabab2a2a2ba2b2) 9 9 9 个,化简可得 s u m = ( 1 + a + a 2 ) × ( 1 + b + b 2 ) sum = (1+a+a^2)\times (1+b+b^2) sum=(1+a+a2×(1+b+b2)

时间复杂度: O ( n × a ) O(n \times \sqrt{a}) O(n×a )

C++代码:

//用 long long 防止溢出
typedef long long LL;

//数据可能非常大,所以需要进行取模处理
const int MOD = 1e9+7;
void divide(int x){
    int old = x;
    //记录质因子,和它的个数
    unordered_map<int,int> cnt;
    for(int i = 2;i <= x/i;i++){
        if(x % i==0){
            while(x % i == 0){
                cnt[i]++;
                x /= i;
            }
        }
    }
    if(x > 1) cnt[x]++; 
    
    LL res = 1;
    for(auto &[k,v]:cnt){
        LL t = 1;
        /*
         v = 1时,t = k + 1
         v = 2时,t = k^2 + k + 1;
         v = 3时,t = k^3 + k^2 + k + 1
        */
         //这里取模也是为了防止溢出
        while(v--) t = (t * k + 1)%MOD;
        res = res * t % MOD;
    }
        cout<<old<<"的约数之和为: "<<res<<"\n";
}

java代码:

   private static final int MOD = (int)Math.pow(10,9);
    public static void divide(int x){
        Map<Integer, Integer> map = new HashMap<>();
        int old = x;
        for(int i = 2;i <= x/i;i++){
            if(x % i == 0){
                while(x % i == 0){
                    map.put(i,map.getOrDefault(i,0)+1);
                    x /= i;
                }
            }
        }
        if(x > 1) map.put(x,1);

        long ans = 1;
        for(Integer key:map.keySet()){
            int v = map.get(key);
            long t = 1;
            while(v>0){
                t = (t * key + 1)% MOD;
                v--;
            }
            ans *= t;
        }
        System.out.println(old +" 的约数之和为: "+ans);
    }

3.例题

1.试除法求约数

题目链接

试除法求约数

题目描述

给定 n n n 个正整数 a i a_i ai,对于每个整数 a i a_i ai,请你按照从小到大的顺序输出它的所有约数。

输入格式

第一行包含整数 n n n

接下来 n n n 行,每行包含一个整数 a i a_i ai

输出格式

输出共 n n n 行,其中第 i i i 行输出第 i i i 个整数 a i a_i ai 的所有约数。

数据范围

  • 1 ≤ n ≤ 100 1≤n≤100 1n100
  • 2 ≤ a i ≤ 2 × 1 0 9 2≤a_i≤2×10^9 2ai2×109

输入样例:

2
6
8 

输出样例:

1 2 3 6 
1 2 4 8 

时间复杂度: O ( n × n ) O(n \times \sqrt{n}) O(n×n )

C++代码:

#include
using namespace std;

int n;

vector<int> get(int x){
    vector<int> res;
    for(int i = 1;i <= x / i;i++){
        if(x % i==0){
            res.push_back(i);
            if(i != x/i) res.push_back(x/i);
        }
    }
    return res;
}

int main(){
    cin>>n;
    while(n--){
        int x;
        cin>>x;
        auto t = get(x);
        sort(t.begin(),t.end());
        for(auto &num:t) printf("%d ",num);
        puts("");
    }
    return 0;
}

2.约数个数

题目链接

约数个数

题目描述

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

输入格式

第一行包含整数 n n n

接下来 n n n 行,每行包含一个整数 a i a_i ai

输出格式

输出一个整数,表示所给正整数的乘积的约数个数,答案需对 1 0 9 + 7 10^9+7 109+7 取模。

输入样例:

3
2
6
8

输出样例:

12

时间复杂度: O ( n × a ) O(n \times \sqrt{a}) O(n×a )

C++代码:

#include
using namespace std;

const int MOD = 1e9+7;
typedef long long LL;

unordered_map<int,int> cnt;
int n;

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

int main(){
    cin>>n;
    LL res = 1;
    while(n--){
        int x;
        cin>>x;
        divide(x);
    }
    for(auto &[k,v]:cnt) res = res * (v + 1) % MOD;
    
    cout<<res<<"\n";
    return 0;
}

3.约数之和

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

输入格式

第一行包含整数 n n n

接下来 n n n 行,每行包含一个整数 a i a_i ai

输出格式

输出一个整数,表示所给正整数的乘积的约数之和,答案需对 1 0 9 + 7 10^9+7 109+7 取模。

输入样例:

3
2
6
8

输出样例:

252

时间复杂度: O ( n × a ) O(n \times \sqrt{a}) O(n×a )

C++代码:

#include
using namespace std;
typedef long long LL;

const int MOD = 1e9+7;
unordered_map<int,int> cnt;
int n;

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

int main(){
    cin>>n;
    while(n--){
        int x;
        cin>>x;
        divide(x);
    }
    
    LL res = 1;
    for(auto &[k,v]:cnt){
        LL t = 1;
        while(v--) t = (t * k + 1)%MOD;
        res = res * t % MOD;
    }
    
    cout<<res<<"\n";
    return 0;
}

你可能感兴趣的:(数论,数论,约数)