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:

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:

  1. c00 -- (numberOfPrimeDivisors % 2 == 0) and (sumOfDivisors % 2 == 0)
  2. c01 -- (numberOfPrimeDivisors % 2 == 0) and (sumOfDivisors % 2 == 1)
  3. c10 -- (numberOfPrimeDivisors % 2 == 1) and (sumOfDivisors % 2 == 0)
  4. 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:

 

  1. If they belong to one class it means that both conditions are met
  2. 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
  3. 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;
}

 

posted @ 2013-05-15 13:54  痴人指路  阅读(264)  评论(0编辑  收藏  举报