目录
唯一分解定理
首先我们来了解一下什么是唯一分解定理。
任何一个正整数,都可以表示(分解)为所有素数(素数又叫质数,是因数只有两个的数)各种幂的积(1 = 任何素数 ^ 0,任何素数 = 自己 ^ 1),并且每个不同的数都只有一种分解,所以叫唯一分解定理。By the way,若一个数依次不被比自己小的素数整除,就可以判断它是素数。两个数的最大公约数就是这两个数的唯一分解式中重合的因子的积。一对互质数的分解中是没有重复的。
如 36 = 2 ^ 2 * 3 ^ 2 ( 2 * 2 * 3 * 3 ), 10 = 2 * 5。
[NOIP2001]最大公约数和最小公倍数问题
题目描述
输入两个正整数x0,y0(1≤x0<100000,1≤y0≤1000000),求出满足下列条件的P,Q的个数 (1) P, Q是正整数 (2) 要求P,Q以x0为最大公约数, 以y0为最小公倍数. 试求:满足条件的所有可能的两个正整数的个数.
输入
x0,y0
输出
满足条件的P,Q的个数
样例输入
3 60
样例输出
4
分析+代码
这道题就要用到数论知识了,因为P,Q 都可以被x0整除,所以P,Q 可以表示为 a*x0 和 b*x0(a,b 为互质的正整数),我们都知道最小公倍数等于两个数的积 / 最大公约数,所以可以得到如下等式:
a*x0 * b*x0 / x0 = y0
∴ a*x0 * b = y0
∴ a * b = y0 / x0
因为上式中全是整数,所以a和b都是 y0 / x0 的互质的因数。可以通过对 y0 / x0 唯一分解来解。
y0 / x0 = p1^w1 * p2^w2 * … * pn^wn .(pi是素数,wi是幂)
就是要从这其中分出两个集合,一个积为a,一个积为b。
因为a和b互质,所以从中分出的两个集合中不能有重复的素数。题目最后要我们求的是有多少对P,Q,就是看有多少种分集合的方法。因此,wi的数量已经不重要了,答案取决于wi >= 1的 pi 的数量。每一个pi都有两种分法,要么去a,要么去b。有两个数就有2 * 2 = 4种分法。n个素数就有2 ^ n种分法。所以,整个代码就是求 y0 / x0 唯一分解式中有效素数的数量n,再输出 2 ^ n。
方法精妙,自己理解:
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
int read() {
int f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s == '-')f = -1;s = getchar();}
while(s >= '0' && s <= '9') {x = x * 10 + s - '0';s = getchar();}
return x * f;
}
int n,m,i,j,k,s,o,num;
template<typename T_>
T_ qkpow(T_ a,int e) {
if(e == 0) return T_(1);
if(e == 1) return a;
return pow(qkpow(a,e / 2),2) * qkpow(a,e % 2);
}
int main() {
n = read();m = read();
if(m % n) {
printf("0\n");
return 0;
}
m /= n;
for(i = 2;i <= n;i ++) {
if(m % i == 0) {
num ++;
while(m % i == 0) m /= i;
//把m中的素数i全都除了,那么接下来判的因数i′就不被前面所有i整除,就是质因数了
}
}
if(m > 1) num ++;
printf("%d",int(pow(2,num)));
return 0;
}
这道题一看代码很简单,数论题基本都有这样的特点,只是需要推理。