Aladdin and the Flying Carpet(唯一分解定理)
题目大意:给两个数a,b,求满足c*d==a且c>=b且d>=b的c,d二元组对数,(c,d)和(d,c)属于同一种情况;
题目分析:根据唯一分解定理,先将a唯一分解,则a的所有正约数的个数为num = (1 + a1) * (1 + a2) *...(1 + ai),这里的ai是素因子的指数,见唯一分解定理,因为题目说了不会存在c==d的情况,因此num要除2,去掉重复情况,然后枚举小于b的a的约数,拿num减掉就可以了。
首先了解唯一分解定理:
题目思路:根据唯一分解定理有:
1.每个数n都能被分解为:n=p1^a1*p2^a2*^p3^a3……pn^an(p为素数);
2.n的正因数的个数sum为:sum=(1+a1)*(1+a2)*(1+a3)……(1+an);
最短边为m,若m>=sqrt(n),则无解。所以m最多我10^6,可遍历找出1-m中n的因子,并用sum去减去这类因子的个数。
代码解析:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5 #define ll long long 6 using namespace std; 7 int const MAX = 1e6 + 10; 8 int p[MAX];//用于存素数 9 bool u[MAX];//u[i]标记数字i是否为素数 10 int num, cnt; 11 ll a, b, tmp; 12 13 void get_prime() 14 { 15 memset(u, false, sizeof(u)); 16 for(int i = 2; i <= sqrt(MAX); i++) 17 if(!u[i]) 18 for(int j = i * i; j <= MAX; j += i) 19 u[j] = true; 20 for(int i = 2; i <= MAX; i++) 21 if(!u[i]) 22 p[cnt ++] = i; 23 } 24 25 //唯一分解定理的正体 26 void cal() 27 { 28 for(int i = 0; i < cnt && p[i] <= sqrt(tmp); i++) 29 { 30 int cc = 0; 31 while(tmp % p[i] == 0) 32 { 33 cc ++; 34 tmp /= p[i]; 35 } 36 num *= (cc + 1); 37 38 } 39 if(tmp > 1) //如果tmp不能被整分,说明还有一个素数是它的约数,此时cc=1 40 num *= 2; 41 } 42 43 int main() 44 { 45 int T; 46 scanf("%d", &T); 47 cnt = 0; 48 get_prime(); 49 for(int ca = 1; ca <= T; ca++) 50 { 51 scanf("%lld %lld", &a, &b); 52 if(a < b * b) 53 printf("Case %d: 0\n", ca); 54 else 55 { 56 num = 1; 57 tmp = a; 58 cal(); 59 num /= 2; 60 for(int i = 1; i < b; i++) 61 if(a % i == 0) 62 num --; 63 printf("Case %d: %d\n", ca, num); 64 } 65 } 66 }
扩展:对一个数N进行分解,求出其分解的结果;
void add_integer(int n,int d) { for(int i=0; i<len; i++) { while(n % primes[i] == 0) { n /= primes[i]; e[i] += d; } if(n == 1)//提前结束,节约时间 break; } }
n是我们要分解的数字,当n在分子上的时候d为1,在分母上的时候d为-1;e数组表示的是i这个数能够分解成几个primes[i]相乘存的数值是primes[i]的次方。
最后把这些数在相乘就可以了。
例如:
100经过分解之后得到的是
e[i]: 2 0 2
primes[i]: 2 3 5
相乘得2^2*5^2=100。