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 }
View Code

 扩展:对一个数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。

posted @ 2019-02-14 21:39  里昂静  阅读(567)  评论(0编辑  收藏  举报