5.15~~Nice Clique
https://www.hackerrank.com/blog/2020editorial
Given n numbers:
D = {d1, d2, …, dn}
what’s the maximum size of a subset of D in which every pair is a ‘nice pair’?
(A, B) is a nice pair iff at least one of the following condition holds.
1. Parity of the number of prime divisors of A is equal to that of B.
2. Parity of the sum of all positive divisors of A is equal to that of B.
Input:
n
d1 d2 … dn
Output:
The maximum size of the subset of D in which every pair is a nice pair
Constraints:
n ≤ 200
0 < d[i] ≤ 10^15
Sample Input:
4
2 3 6 8
Sample Output:
3
Explanation:
d[i] | prime divisors (count) | divisors (sum) |
2 | 2 (1) | 1,2 (3) |
3 | 3 (1) | 1,3 (4) |
6 | 2,3 (2) | 1,2,3,6 (12) |
8 | 2 (1) | 1,2,4,8 (15) |
==> (d1, d2) nice pair
(d1, d3) not
(d1, d4) nice
(d2, d3) nice
(d2, d4) nice
(d3, d4) not
==> max subset{2, 3, 8}. ==> S = 3.
Challenge 4: Nice Clique
We need to do exactly what described in the statement: find number of prime divisors and sum of all positive divisors.
Let's start with 80% solution and find prime divisors using "for" cycle from 2 to sqrt(n) and calculate sum of divisors using canonical number representation:
If x = p1α1 * p2α2 * ... * pnαn, then sum of divisors of x is equal to
(1 + p1 + p12 + .. + p1α1 * (1 + p2 + ... + p2α2) * ... * (1 + pn + pn2 + ... + pnαn)
Proof: every summand is a divisor of x, and every divisor of x equals to some summand in this formula.
for (long j = 2; j * j <= a; j++) { if (a % j == 0) { numberOfPrimeDivisors++; long currentValue = 1; long currentSum = 1;//(1 + x + x^2 + ..) * (1 + y + y ^2 + ...) + ... while (a % j == 0) { a /= j; currentValue *= j; currentSum += currentValue; } sumOfDivisors = (sumOfDivisors * currentSum) % 2; } }
After we got these numbers, we can specify a class for each number:
- c00 -- (numberOfPrimeDivisors % 2 == 0) and (sumOfDivisors % 2 == 0)
- c01 -- (numberOfPrimeDivisors % 2 == 0) and (sumOfDivisors % 2 == 1)
- c10 -- (numberOfPrimeDivisors % 2 == 1) and (sumOfDivisors % 2 == 0)
- c11 -- (numberOfPrimeDivisors % 2 == 1) and (sumOfDivisors % 2 == 1)
Answer is the maximal sum of size of the two neigthboring(differing in one digit) classes(i.e. max(c00 + c01, c00 + c10, c11 + c10, c11 + c01), because if we take two random numbers from answer set:
- If they belong to one class it means that both conditions are met
- If they belong to "neighboring" class(c00 and c01, c11 and c10, but not, for example, c00 and c11) it means that one of these conditions is true
- If they belong to (c00 and c11) or (c01 and c10) it means neither of these conditions is met and such elements coudn't be in answer set
To speed up this solution and get a full score I have generated list of prime divisors with Sieve of Eratosthenes/ up to sqrt(max number)
#include <cmath> #include <cstdio> #include <vector> #include <iostream> #include <algorithm> using namespace std; long long mul(long long x, long long y, long long mod) { if (x == 0) return 0; else { long long v = mul(x / 2, y, mod); return ((v+v)%mod+((x%2==0)?0:y))%mod; } } long long power_mod(long long x, long long e, long long mod) { return (e == 0) ? 1 : mul(power_mod(mul(x, x, mod), e / 2, mod), (e % 2 == 0) ? 1 : x, mod); } // Miller Rabin bool isPrime(long long n) { int r = 0; long long R = n - 1; while (R % 2 == 0) { r++; R /= 2; } for (int it = 1; it <= 10; it++) { long long a = 1 + rand() % (n - 1); long long a_R (power_mod(a, R, n)); vector<long long> b (r + 1); b[0] = a_R; for (int i = 1; i <= r; i++) { b[i] = mul(b[i - 1], b[i - 1], n); } if (b[r] != 1) { return false; } if (b[0] == 1) { continue; } int j = -1; for (int i = 0; i <= r; i++) { if (b[i] != 1) { j = i; } } if (b[j] == n - 1) { continue; } else { return false; } } return true; } bool isSquare(long long n) { long long l = 0, r = 1; while (r * r < n) r *= 2; while (l != r) { long long m = (l + r) / 2; (m * m < n) ? (l = m + 1) : (r = m); } return l * l == n; } int calc(long long n) { bool divisibleBy2 = n % 2 == 0; while (n % 2 == 0) n /= 2; // n odd int nFactors = int (divisibleBy2); int divSumParity = 1; for (int i = 2; (long long) i * i * i <= n; i ++) { if (n % i == 0) { int e = 0; while (n % i == 0) n /= i, e ++; if (e % 2 == 1) divSumParity = 0; nFactors ++; } } if (n > 1) { if (isSquare(n)) { nFactors += 1; } else if (isPrime(n)) { nFactors += 1; divSumParity = 0; } else { nFactors += 2; divSumParity = 0; } } return 2*(nFactors%2) + divSumParity; } inline int TWO(int n) { return 1 << n; } inline int All1(int n) { return TWO(n) - 1; } int main() { srand(0); vector<int> freq (4); int n; cin >> n; for (; n > 0; n --) { long long x; cin >> x; freq[calc(x)] ++; } cout << max(freq[0], freq[3]) + max(freq[1], freq[2]) << endl; /* Enter your code here. Read input from STDIN. Print output to STDOUT */ return 0; }