D. Divisors
http://codeforces.com/contest/1033/problem/D
题意:
给n个(n<=500)个数,($a_i <= 2 imes 10 ^ {18}$),每个数的因数个数在[3,5]内。$a = prodlimits_{i=1}^na_i$,求a的因数个数。
分析:
首先有一个结论:一个数x的质因数分解后为:$x = p_1^{a_1}p_2^{a_2}...p_k^{a_k}$ 那么它的因数个数就是 $(a_1 + 1) imes (a_2 + 1) imes ... imes (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 }