/*
PROBLEM: Maximize Pairs with Different Square-Free Kernels
Given:
- N numbers in an array
- K operations allowed
- Each operation changes a number to have a new unique kernel
Square-Free Kernel Definition:
- For a number, factor it into primes
- Multiply only the primes that appear an ODD number of times
- Example: 72 = 2^3 * 3^2 → kernel = 2 (only 2 appears odd times)
- Example: 50 = 2 * 5^2 → kernel = 2 (only 2 appears odd times)
- Example: 18 = 2 * 3^2 → kernel = 2
Goal: Two numbers form a "good pair" if their kernels are DIFFERENT.
Maximize the number of good pairs.
Key Insight:
- If all N numbers have different kernels → we can make N/2 pairs (all good)
- If many numbers share the same kernel → they can't pair with each other
- We can use K operations to move numbers to new unique kernels
- Strategy: Reduce the maximum frequency of any kernel
Approach:
1. Calculate kernel for each number
2. Count how many numbers have each kernel
3. Binary search: what's the minimum max-frequency we can achieve with K ops?
4. Answer = min(N/2, N - final_max_freq)
- N/2 is the max possible pairs
- N - max_freq is how many can pair with different kernels
Time: O(N√M + log(max_freq) * unique_kernels) where M is max element
*/
#include <bits/stdc++.h>
using namespace std;
// Sieve of Eratosthenes: find all prime numbers up to limit
vector<int> sieve(int lim) {
vector<bool> ok(lim + 1, true);
ok[0] = ok[1] = false; // 0 and 1 are not prime
// Mark multiples of each prime as not prime
for (int i = 2; i * i <= lim; i++) {
if (ok[i]) {
// Mark all multiples of i starting from i*i
for (int j = i * i; j <= lim; j += i) {
ok[j] = false;
}
}
}
// Collect all primes
vector<int> p;
for (int i = 2; i <= lim; i++) {
if (ok[i]) p.push_back(i);
}
return p;
}
// Calculate square-free kernel of x
// Kernel = product of all prime factors with ODD exponent
long long calc(long long x, const vector<int>& p) {
long long res = 1;
// Check each prime up to sqrt(x)
for (int pr : p) {
if ((long long)pr * pr > x) break;
// Count how many times pr divides x
int cnt = 0;
while (x % pr == 0) {
x /= pr;
cnt++;
}
// If exponent is odd, include this prime in kernel
if (cnt & 1) res *= pr;
}
// If x > 1 remains, it's a prime factor with exponent 1 (odd)
if (x > 1) res *= x;
return res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
long long k;
cin >> n >> k;
vector<long long> a(n);
long long mx = 0;
for (int i = 0; i < n; i++) {
cin >> a[i];
mx = max(mx, a[i]); // Track maximum value
}
// Edge case: can't form pairs with less than 2 elements
if (n < 2) {
cout << 0 << "\n";
return 0;
}
// Generate all primes up to sqrt(max_value)
// We only need primes up to sqrt because larger primes appear with exponent 1
int sq = (int)sqrt(mx);
vector<int> p = sieve(max(1, sq));
// Calculate kernel for each number and count frequencies
map<long long, int> cnt;
for (long long x : a) {
long long ker = calc(x, p);
cnt[ker]++;
}
// Extract all frequency values
vector<int> f;
int mf = 0; // Maximum frequency
for (auto [ker, c] : cnt) {
f.push_back(c);
mf = max(mf, c);
}
// Binary search to find minimum achievable max frequency with k operations
int lo = 1, hi = mf;
// Check if we can reduce all frequencies to at most t using k operations
auto check = [&](int t) -> bool {
long long ops = 0; // Operations needed
for (int c : f) {
// If frequency c > t, we need to move (c - t) elements
if (c > t) {
ops += (c - t);
if (ops > k) return false; // Too many operations needed
}
}
return true; // Can achieve with <= k operations
};
// Binary search: find smallest t such that check(t) is true
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (check(mid)) {
hi = mid; // Can achieve mid, try smaller
} else {
lo = mid + 1; // Can't achieve mid, need larger
}
}
int best = lo; // Best max frequency we can achieve
// Maximum pairs possible = n/2 (each pair uses 2 elements)
long long total = n / 2;
// Elements that can pair with different kernels = n - best
// (If max freq is 'best', at most 'best' elements share same kernel)
// Answer is minimum of: total possible pairs, or elements with different kernels
long long ans = min(total, (long long)(n - best));
cout << ans << "\n";
return 0;
}