问题描述
蓝桥村是蓝桥王国年年的模范村,这是因为他们村的稻田每年都是优美的。
对于一块稻田来说,如果其中任意两根不同的秧苗的高度乘积均为完全平方数,该稻田被称之为优美的稻田。
蓝桥王国的稻田验收日即将到来,但现在蓝桥村还有一块插了 𝑁 根秧苗的稻田不够优美,其中第 𝑖 根秧苗的高度为 ℎ𝑖。
作为蓝桥杯的村长,你可以发动技能拔苗助长:
- 选择一个质数 x (2 ≤ x ≤ 10^6) ,同时将任意一株高度为 ℎ 的秧苗变为 ℎ×𝑥。
请问你最少需要发动多少次拔苗助长才可以将该稻田变得优美。
输入格式
第一行输入一个整数 𝑁 (1 ≤ 𝑁 ≤ 10^5) 表示稻田中秧苗的数量。
第二行输入 𝑁N 个整数 ℎ1,ℎ2,ℎ3,⋯,ℎ𝑁 (1 ≤ 𝐴𝑖 ≤ 10^6) 表示秧苗的高度。
输出格式
输出一个整数表示答案。
输入样例
5
1 2 3 4 5
输出样例
3
解题思路
题目说让每两个数相乘都是一个完全平方数,这里不难想到分解质因数,如果要满足这个要求,则需要任意两个数相乘,其所有质因数都是偶数个数。
对于任意质因数p,任意两个数相乘的结果中p的个数为偶数,则说明两个数中的p的个数要么都是奇数,要么都是偶数;反过来说,如果存在任意两个数a和b,假设a的质因数2的个数为1个,那么b的质因数2的个数如果是偶数,则a和b相乘的结果必不可能是完全平方数。
因此我们考虑对于每一个数x进行统计,计算其所有质因数出现的次数,对于某个质因数p,如果其对于某个x出现的次数为奇数,就记录一次;这样的目的是方便我们最终考虑是将每个数中的p都变成奇数个还是偶数个。
举一个具象化的例子,对于一个数列2 2 2 3:对质因数2来说,有三个x存在奇数个2;对质因数3来说,有一个x存在奇数个3。上述情况中,我们应该选择将所有x中质因数2的个数补齐到奇数个,这样只需要操作4 - 3 = 1次;而对于质因数3,我们应该选择补齐到偶数个,这样只需要操作1次。
所以可以考虑到,对于每个质因数p,其在每个x中出现奇数次的次数num,对答案的贡献是min(num, n - num)。
为了记录每一个x的每一个质因数的个数,我们可以使用Map数据结构,同时可以使用埃氏筛加快这个过程,我们筛选出log(N)以内所有质数逐一测试,如果在试除计算的最后没有变成1,则其本身就是一个质数,即自己的一个质因数。
import java.util.*;public class Main {static final int inf = (int) 1e9;static final int N = (int) Math.sqrt(1e6 + 1);static boolean[] prime;static ArrayList<Integer> primeList;public static void main(String[] args) {e_sieve();System.out.println(primeList);Scanner sc = new Scanner(System.in);int n = sc.nextInt();Map<Integer, Integer> mapAll = new HashMap<Integer, Integer>();for (int i = 0; i < n; i++) {int temp = sc.nextInt();Map<Integer, Integer> map = new HashMap<Integer, Integer>();for (int e : primeList) {while (temp % e == 0) {temp /= e;map.put(e, map.getOrDefault(e, 0) + 1);}if (temp == 1) {break;}}if (temp != 1) {map.put(temp, 1);}for (java.util.Map.Entry<Integer, Integer> e : map.entrySet()) {if (e.getValue() % 2 == 1) {mapAll.put(e.getKey(), mapAll.getOrDefault(e.getKey(), 0) + 1);}}}System.out.println(mapAll);long ans = 0;for (int e : mapAll.values()) {ans += Math.min(e, n - e);}System.out.print(ans);}static void e_sieve() {primeList = new ArrayList<Integer>();prime = new boolean[N];Arrays.fill(prime, true);prime[0] = false; prime[1] = false;for (int i = 2; i < N; i++) {if (prime[i]) {primeList.add(i);for (long j = 1L * i * i; j < N; j += i) {prime[(int)j] = false;}}}}
}