合适数对(数据加强版)
思路:
我们考虑一个数什么时候可以表示为\(x ^ {k}\),先把\(x\)进行质因数分解可以得到\(x = p_{1}^{t_1} * p_{2} ^ {t_2} \dots * p_{n} ^ {t_n}\),所以\(x ^ {k}\)就可以表示为\(x ^ {k} = p_{1} ^ {k_1} * p_{2} ^ {k_2} \dots * p_{n} ^ {k_n}\), 其中\(k_1, k_2, k_3 \dots k_t\) 都是\(k\)的倍数
所以我们在考虑\(p*q=x^{k}\)的时候,只需要保证\(p * q\)分解质因数的结果中每一个因数的指数都可以被\(k\)整除。那么我们对序列中每一个数进行质因数分解的时候,对于每一个质因数的幂次都\(\%k\)并将结果存在\(p\)中,即\(p = p_{1} ^ {k_1} * p_{2} ^ {k_2} \dots * p_{n} ^ {k_n}\), 在我们得到\(p\)之后,我们只需要判断我们可以求得有多少个匹配的\(q\)并更新答案。
由于数据量达到了\(10 ^ {7}\),如果用\(O(\sqrt{n})\)的朴素判素数明显是不行的,所以我们应该用欧拉筛\(O(n)\)来求的所有数的最小质因子。当然我们在筛素数的时候很明显所有的偶数都是一定会被\(2\)给筛掉的,所以我们在筛素数的时候可以直接将所有的偶数跳过,不对它们筛素数,这样可以优化一下筛法的常数。
void Eular(int n) { prime[idx ++ ] = 2; minp[2] = 2; st[2] = true; for (int i = 3; i <= n; i += 2) { if (!st[i]) prime[idx ++ ] = i, minp[i] = i, st[i] = true; for (int j = 0; prime[j] * i <= n; j ++ ) { st[prime[j] * i] = true; minp[prime[j] * i] = prime[j]; if (i % prime[j] == 0) break; } } }
\(code\)
int n, k; n = read(), k = read(); std::vector<int> a(n); for (auto &I : a) I = read(); int mx = *max_element(a.begin(), a.end()); Eular(mx); std::vector<i64> mp(mx + 1); i64 ans = 0; for (int i = 0; i < n; i ++ ) { i64 p = 1, q = 1; while (a[i] > 1) { int val = (a[i] & 1) ? minp[a[i]] : 2; int cnt = 0; while (a[i] % val == 0) { cnt ++ ; a[i] /= val; } while (cnt >= k) cnt -= k; p *= qmi(val, cnt); if (cnt) q *= qmi(val, k - cnt); if (q < 0 || q > mx) q = 0; } ans += mp[q]; mp[p] ++; } printf("%lld\n", ans);