CF 1033 D. Divisors

D. Divisors

http://codeforces.com/contest/1033/problem/D

题意:

  给n个(n<=500)个数,($a_i <= 2 \times 10 ^ {18}$),每个数的因数个数在[3,5]内。$a = \prod\limits_{i=1}^na_i$,求a的因数个数。

分析:

  首先有一个结论:一个数x的质因数分解后为:$x = p_1^{a_1}p_2^{a_2}...p_k^{a_k}$ 那么它的因数个数就是 $(a_1 + 1) \times (a_2 + 1) \times ... \times (a_k + 1)$。

  于是这道题就可以求出每个质因数的个数,然后将指数+1相乘即可。

  但是$a_i$太大了,无法直接求质因数。

  因为每个数的因数个数在[3,5]范围内,所以根据上面的结论,可以知道每个数的质因数分解只有四种形式:$pq, p^2, p^3,p^4$。后三种直接二分就能算出其质因数,用map记录每个质因数的指数。

  对于第一种,直接求质因数是不可能的了,考虑能否不求质因数,而计算答案。首先对于所有数二分,如果不能分成后三种,那么将其记录到b数组中。b中的一个数拆成第一种形式后,p和q,在map都没出现过,那么我们可以知道它的贡献就是(2*2)了(不考虑后面的)。如果p和q中有一个出现过了,我们必须要合并他们的幂。

  如何合并幂:枚举b[i],枚举a数组中的所有数,求gcd,如果1<gcd<b[i],那么可以说明b[i]和a[j]分解后的都有gcd,(b[i]=pq,gcd=p或者q)。

  对于剩下的数,每一个分解后的质数都是还未出现过,直接计算答案。

代码: 

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 #include<cctype>
 7 #include<set>
 8 #include<vector>
 9 #include<queue>
10 #include<map>
11 #define fi(s) freopen(s,"r",stdin);
12 #define fo(s) freopen(s,"w",stdout);
13 using namespace std;
14 typedef long long LL;
15 
16 inline LL read() {
17     LL x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
18     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
19 }
20 
21 const int N = 505;
22 const int mod = 998244353;
23 const LL INF = 9e18;
24 
25 LL a[N], b[N], c[N];
26 map<LL,int> f;
27 LL Sqrt(LL x,int k) {
28     LL l = 1, r; // 虽然现在的l,r在int范围内,但是也要开longlong!!!!!
29     if (k == 2) r = 1414213563;
30      if (k == 3) r = 1259922;
31      if (k == 4) r = 37607;
32     while (l <= r) {
33         LL mid = (l + r) >> 1;
34         LL t = 1;
35         for (int i=1; i<=k; ++i) t = 1ll * t * mid;
36         if (t == x) return mid;
37         else if (t > x) r = mid - 1;
38         else l = mid + 1;
39     }
40     return -1;
41 }
42 LL gcd(LL a,LL b) {
43     return b == 0 ? a : gcd(b, a % b);
44 }
45 int main() { 
46     int n = read();
47     for (int i=1; i<=n; ++i) a[i] = read();
48 
49     for (int i=1; i<=n; ++i) {
50         bool flag = 0;
51         for (int k=4; k>=2; --k) { // 从大到小!!! 
52             LL p = Sqrt(a[i], k);
53             if (p != -1) { f[p] += k; flag = 1; break; }
54         }
55         if (!flag) b[i] = a[i];
56     }    
57     for (int i=1; i<=n; ++i) {
58         if (!b[i]) continue;
59         bool flag = 0;
60         for (int j=1; j<=n; ++j) {
61             if (i == j) continue;
62             LL d = gcd(b[i], a[j]);
63             if (d != 1 && d != b[i]) {
64                 flag = 1; f[d] ++; f[b[i] / d] ++; break;
65             }
66         }
67         if (!flag) c[i] = b[i];
68     }
69     LL ans = 1;
70     for (int i=1; i<=n; ++i) {
71         if (!c[i]) continue;
72         LL cnt = 2;
73         for (int j=1; j<=n; ++j) 
74             if (i != j && c[i] == c[j]) cnt ++, c[j] = 0;
75         cnt = cnt * cnt % mod;
76         ans = ans * cnt % mod;
77     }
78     map<LL,int> :: iterator it;
79      for (it=f.begin(); it!=f.end(); it++) 
80          ans = (ans * (it->second + 1)) % mod;
81 //    for (auto p: f) ans = (ans * (p.second + 1)) % mod;
82     cout << ans;
83      fflush(stdout);
84     return 0;
85 }

 

posted @ 2018-10-08 15:14  MJT12044  阅读(608)  评论(0编辑  收藏  举报