/*
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;
// Find all primes up to limit
vector<int> sieve(int lim) {
vector<bool> ok(lim + 1, true);
ok[0] = ok[1] = false;
for (int i = 2; i * i <= lim; i++) {
if (ok[i]) {
for (int j = i * i; j <= lim; j += i) {
ok[j] = false;
}
}
}
vector<int> p;
for (int i = 2; i <= lim; i++) {
if (ok[i]) p.push_back(i);
}
return p;
}
// Get square-free kernel: multiply primes with odd exponent
long long calc(long long x, const vector<int>& p) {
long long res = 1;
for (int pr : p) {
if ((long long)pr * pr > x) break;
int cnt = 0;
while (x % pr == 0) {
x /= pr;
cnt++;
}
// If odd exponent, include this prime
if (cnt & 1) res *= pr;
}
// If x > 1 now, it's a prime with exponent 1
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]);
}
if (n < 2) {
cout << 0 << "\n";
return 0;
}
// Get primes up to sqrt(max)
int sq = (int)sqrt(mx);
vector<int> p = sieve(max(1, sq));
// Count kernel frequencies
map<long long, int> cnt;
for (long long x : a) {
long long ker = calc(x, p);
cnt[ker]++;
}
// Extract frequencies
vector<int> f;
int mf = 0;
for (auto [ker, c] : cnt) {
f.push_back(c);
mf = max(mf, c);
}
// Binary search: minimum achievable max frequency
int lo = 1, hi = mf;
// Check if we can reduce all frequencies to at most t
auto check = [&](int t) -> bool {
long long ops = 0;
for (int c : f) {
if (c > t) {
ops += (c - t);
if (ops > k) return false;
}
}
return true;
};
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (check(mid)) {
hi = mid;
} else {
lo = mid + 1;
}
}
int best = lo;
// Maximum pairs we can form
long long total = n / 2;
// Answer: min of total pairs or (n - max_freq)
long long ans = min(total, (long long)(n - best));
cout << ans << "\n";
return 0;
}