数学问题——质因子分解

  所谓质因子分解是指将一个正整数 n 写成一个或多个质数的乘积形式,例如 24=2*2*2*3。显然,由于最后都要归结到若干不同质数的乘积,不妨先把素数表打印出来。

  由于每个质因子都可以不止出现一次,因此不妨定义结构体 factor ,用来存放质因子及其个数,如下所示:

1 struct factor {
2     int x, cnt;    // x 为质因子,cnt 为其个数
3 } fac[10]; 

  而有一个结论:对一个正整数 n 来说,如果它存在 [2,n] 范围内的质因子,要么这些质因子全部小于等于 sqrt(n) ,要么只存在一个大于 sqrt(n) 的质因子,而其余质因子全部小于等于 sqrt(n) 。这就给进行质因子分解提供了一个很好的思路:

  1. 枚举 1~sqrt(n) 范围内的所有质因子 p,判断 p 是否是 n 的因子。如果 p 是 n 的因子,那么给 fac 数组中增加质因子 p ,并初始化其个数为 0。然后只要 p 还是 n 的因子,就让 n 不断除以 p,每次操作令 p 的个数加 1,直到 p 不再是 n 的因子为止。

1 if(n % pri[i] == 0) {    // prime[i] 是质因子
2     fac[num].x = pri[i];
3     fac[num].cnt = 0;
4     while(n%pri[i] == 0) { // 计算该质因子的个数
5         fac[num].cnt++;
6         n /= pri[i];
7     }
8     num++;    // 不同质因子个数 +1
9 }

  2. 如果在上面步骤结束后 n 仍然大于 1,说明 n 有且仅有一个大于 sqrt(n) 的质因子,这时需要把这个质因子加入 fac 数组,并令其个数为 1。

1 if(n != 1) { // 存在大于 sqrt(n) 的质因子
2     fac[num].x = n;
3     fac[num++].cnt = 1;
4 } 

  至此,fac 数组中存放的就是质因子分解的结果,时间复杂度为O($\sqrt{n}$)。 

【PAT A1059】Prime Factors

  题目:Given any positive integer N, you are supposed to find all of its prime factors, and write them in the format N = p1^k1 * p2^k2 *…*pm^km.

  题意:给出一个 int 范围的整数,按照从小到大的顺序输出其分解为质因数的乘法算式。

  思路:见上面讲解

  下面为程序的完整代码:

/*
    质因子分解
*/

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>

typedef struct{
    int x, cnt;    // x 为质因子,cnt 为其个数
} factor;
factor fac[10]; 

#define maxn 100010
int pri[maxn], pNum=0;
bool p[maxn] = {0};    // 表示数是否被筛掉

// 素数表的获取,埃氏筛选
void findPrime() {
    int i;
    for(i=2; i<maxn; ++i) {
        if(!p[i]) {                // 没有被筛掉,为素数
            pri[pNum++] = i;
            int j;
            for(j=i+i; j<maxn; j+=i) {    // 筛掉倍数
                p[j] = true;
            }
        }
    }
} 

int num=0;    // 表示 n 不同质因子个数
void findFactor(int n) {
    if(n==1) return;
    int sqr = (int)sqrt(n*1.0);
    int i;
    for(i=0; i<pNum && pri[i]<=sqr; ++i) {    // 枚举 1~sqrt(n) 的所有质因子
        if(n % pri[i] == 0) {    // prime[i] 是质因子
            fac[num].x = pri[i];
            fac[num].cnt = 0;
            while(n%pri[i] == 0) { // 计算该质因子的个数
                fac[num].cnt++;
                n /= pri[i];
            }
            num++;    // 不同质因子个数 +1
        }
        if(n == 1)    break;
    }
    if(n != 1) { // 存在大于 sqrt(n) 的质因子
        fac[num].x = n;
        fac[num++].cnt = 1;
    }
}  

int main() {
    findPrime();        // 生成素数表
    int n;
    scanf("%d", &n);
    findFactor(n);        // 求质因子
    int i;
    // 按格式输出
    printf("%d=", n);
    if(n==1) printf("1");
    else {
        for(i=0; i<num; ++i) {
            if(i>0) printf("*");
            printf("%d", fac[i].x);
            if(fac[i].cnt > 1) {
                printf("^%d", fac[i].cnt);
            }
        }
    }  

    return 0;
}

  最后指出,如果要求一个正整数 N 的因子个数,只需要对其质因子分解,得到各质因子 pi 的个数分别为 e1、e2、... 、ek,于是 N 的因子个数就是 (e1 + 1)*(e2 + 1)*...*(ek + 1)。

原文地址:https://www.cnblogs.com/coderJiebao/p/Algorithmofnotes14.html

时间: 2024-08-29 01:56:20

数学问题——质因子分解的相关文章

hdoj 1492 The number of divisors(约数) about Humble Numbers 【数论】【质因子分解 求和】

定理:一个正整数 n 可以用素因子唯一表示为 p1^r1 * p2^r2 * ... pk^rk (其中 pi 为素数) , 那么这个数的因子的个数就是,(r1+1)*(r2+1)*...*(rk+1). 理解:为什么是加1之后再相乘,因为一个数的的因子数至少为1和他自身,但因为r1,r2..可以为0,所以因子的个数为(r1+1)... 拓展一下: 定理1: 一个正整数 n 可以用素因子唯一表示为 p1^r1 * p2^r2 * ... pk^rk (其中 pi 为素数) , 那么这个数的因子的

BZOJ 1485: [HNOI2009]有趣的数列 [Catlan数 质因子分解]

1485: [HNOI2009]有趣的数列 Description 我们称一个长度为2n的数列是有趣的,当且仅当该数列满足以下三个条件: (1)它是从1到2n共2n个整数的一个排列{ai}: (2)所有的奇数项满足a1<a3<…<a2n-1,所有的偶数项满足a2<a4<…<a2n: (3)任意相邻的两项a2i-1与a2i(1≤i≤n)满足奇数项小于偶数项,即:a2i-1<a2i. 现在的任务是:对于给定的n,请求出有多少个不同的长度为2n的有趣的数列.因为最后的答

HDU 2601 An easy problem(暴力枚举/质因子分解)

An easy problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 7963    Accepted Submission(s): 1920 Problem Description When Teddy was a child , he was always thinking about some simple math p

luogu P2043 质因子分解

题目描述 对N!进行质因子分解. 输入输出格式 输入格式: 输入数据仅有一行包含一个正整数N,N<=10000. 输出格式: 输出数据包含若干行,每行两个正整数p,a,中间用一个空格隔开.表示N!包含a个质因子p,要求按p的值从小到大输出. 输入输出样例 输入样例#1: 10 输出样例#1: 2 8 3 4 5 2 7 1 说明 10!=3628800=(2^8)*(3^4)*(5^2)*7 质因数分解.. #include<cstdio> const int maxn=100006;

POJ1845:Sumdiv(求因子和+逆元+质因子分解)好题

题目链接:http://poj.org/problem?id=1845 定义: 满足a*k≡1 (mod p)的k值就是a关于p的乘法逆元. 为什么要有乘法逆元呢? 当我们要求(a/b) mod p的值,且a很大,无法直接求得a/b的值时,我们就要用到乘法逆元. 我们可以通过求b关于p的乘法逆元k,将a乘上k再模p, 即(a*k) mod p.其结果与(a/b) mod p等价. 题目解析:让求a^b的因子和modk,因为是大数没法直接求,因为求因子和函数是乘性函数,所以首先要质因子分解,化成n

uva10780 质因子分解

UVA - 10780 Again Prime? No Time.(uva卡得一逼,所以还是把vj的链接贴一下把) 题意:给出n,m,使得m^k是n!的因子,求最大的k 思路:质因子分解,将m 和n!都分解为 p1^a1*p2^a2*...pn^an,其中p1 p2...pn是连续的质数2,3,5,7...,用一个数组记录每个质数的次幂ai,然后二分答案k,只有当m分解的质因子的次幂*k全部小于等于n!分解的质因子次幂,m^k才是n!的因子,比较坑的一点是,当k=0时是作为无解的情况的 AC代码

hdu5392--Infoplane in Tina Town(置换群+质因子分解求最小公倍数)

题目链接:点击打开链接 题目大意:给出一种操作a[1],a[2],,,,a[n],代表每交换一次,1位置的数到a[1]位置,2位置的数到a[2]位置,,, 问最终交换多少次可以恢复初始的情况. 题目给出一个置换,要求置换的次数,也就是所有轮换个数的最小公倍数.首先求出所有轮换的个数,然后求最小公倍数的时候不能用gcd,因为Mod的取余太大,所以用质因子分解,统计每个质因子出现的最多次数,计算最终的值. #include <cstdio> #include <cstring> #in

UVA - 10780 Again Prime? No Time. (质因子分解)

Description Again Prime? No time. Input: standard input Output: standard output Time Limit: 1 second The problem statement is very easy. Given a number n you have to determine the largest power of m, not necessarily prime, that divides n!. Input The

P2043 质因子分解

题目描述 对N!进行质因子分解. 输入输出格式 输入格式: 输入数据仅有一行包含一个正整数N,N<=10000. 输出格式: 输出数据包含若干行,每行两个正整数p,a,中间用一个空格隔开.表示N!包含a个质因子p,要求按p的值从小到大输出. 输入输出样例 输入样例#1: 复制 10 输出样例#1: 复制 2 8 3 4 5 2 7 1 说明 10!=3628800=(2^8)*(3^4)*(5^2)*7 哦哟,怎么这么多长得这么像的题啊... 全都是质因数质因数. 哦不对,这个是质因子hhh.