hihoCoder1284机会渺茫(唯一分解定理 + 约分)

题目链接

#1284 : 机会渺茫

时间限制:5000ms
单点时限:1000ms
内存限制:256MB

描述

小Hi最近在追求一名学数学的女生小Z。小Z其实是想拒绝他的,但是找不到好的说辞,于是提出了这样的要求:对于给定的两个正整数N和M,小Hi随机选取一个N的约数N',小Z随机选取一个M的约数M',如果N'和M'相等,她就答应小Hi。

小Z让小Hi去编写这个随机程序,到时候她review过没有问题了就可以抽签了。但是小Hi写着写着,却越来越觉得机会渺茫。那么问题来了,小Hi能够追到小Z的几率是多少呢?

输入

每个输入文件仅包含单组测试数据。

每组测试数据的第一行为两个正整数N和M,意义如前文所述。

对于40%的数据,满足1<=N,M<=10^6

对于100%的数据,满足1<=N,M<=10^12

输出

对于每组测试数据,输出两个互质的正整数A和B(以A分之B表示小Hi能够追到小Z的几率)。

样例输入
3 2
样例输出
4 1

分析:对 n 和 m 分解,得到n和m的每一个素数的指数en[],em[],然后取公约数,即取每个指数小的那个得到新的 et[], sum(et[]) / sum(en[]) * sum(em[])即所求,就是在en里面找一个,在em里面找一个,1/(sum[en] * sum[em]),一共有sum[et]个
题目等级为2,然后我却WA了好几次,RE了好几次 =_=...
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 using namespace std;
 5 typedef long long LL;
 6 const int Max = 10000000 + 5; //开到6次RE
 7 bool flag[Max + 5];
 8 int prime[Max + 5], tot;
 9 int en[Max + 5], em[Max + 5], et[Max + 5];
10 void get_prime()
11 {
12     memset(flag, false, sizeof(flag));
13     tot = 0;
14     for (int i = 2; i <= Max;i ++)
15     {
16         if (!flag[i])
17         {
18             prime[++tot] = i;
19             for (int j = i; j <= Max / i; j++)
20                 flag[i * j] = true;
21         }
22     }
23 }
24 void get_fact(LL n, int * temp)
25 {
26     memset(temp, 0, sizeof(temp));
27     for (int i = 1; i <= tot; i++)
28     {
29         if (prime[i] > n)
30             break;
31         if (n % prime[i] == 0)
32         {
33             while (n % prime[i] == 0)
34             {
35                 n = n / prime[i];
36                 temp[prime[i]]++;
37             }
38         }
39     }
40     if (n > 1)
41         temp[n]++;
42 }
43 LL get_sum(int temp[])
44 {
45     LL sum = 1;
46     for (int i = 1; i <= tot; i++)
47     {
48         if (temp[prime[i]])
49             sum *= (temp[prime[i]] + 1);
50     }
51     return sum;
52 }
53 void solve()
54 {
55     memset(et, 0, sizeof(et));
56     for (int i = 1; i <= tot; i++)
57     {
58         if (en[prime[i]] && em[prime[i]])
59         {
60             int minn = min (en[prime[i]], em[prime[i]]);  //取最小的指数
61             et[prime[i]] += minn;
62         }
63     }
64 }
65 LL get_gcd(LL a, LL b)
66 {
67     if (b == 0)
68         return a;
69     return get_gcd(b, a % b);
70 }
71 int main()
72 {
73     get_prime();
74     LL n, m;
75     scanf("%lld%lld", &n, &m);
76     get_fact(n, en);
77     get_fact(m, em);
78     solve();
79     LL numn = get_sum(en);
80     LL numm = get_sum(em);
81     LL numf = get_sum(et);
82 
83    // 最后结果就是 numf / (numn * numm)
84    所以先对numf 和 numn约分,
85   然后把约分后的numf与numm约分,最后numn * numm
86     LL x1 = numf;
87     LL t1 = get_gcd(numn, numf);
88     x1 = x1 / t1;   
89     numn = numn / t1;
90 
91     LL t2 = get_gcd(numm, x1);
92     x1 = x1 / t2;
93     numm = numm / t2;
94     numn = numn * numm;
95 
96     printf("%lld %lld
", numn, x1);
97     return 0;
98 }
View Code
原文地址:https://www.cnblogs.com/zhaopAC/p/5326429.html