C 合适数对
Link:合适数对
题意:
给定一个长度为 n n n的正整数数列 a 1 , a 2 , … , a n a1,a2,…,an a1,a2,…,an 和一个正整数 k k k。
请你判断共有多少个数对 ( l , r ) (l,r) (l,r) 同时满足:
- 1 ≤ l < r ≤ n 1 \leq l < r\leq n 1≤l<r≤n
- 存在一个整数 x x x使得 a l ? a r = x k a_l * a_r = x^k al??ar?=xk成立。
数据范围:
2 ≤ n ≤ 1 0 5 2 \leq n \leq 10^5 2≤n≤105 , 2 ≤ k ≤ 100 2\leq k \leq 100 2≤k≤100, 1 ≤ a i ≤ 1 0 5 1 \leq a_i \leq 10^5 1≤ai?≤105.
输入样例:6 3
1 3 9 8 24 1输出样例:
5
分析:
设 满足条件的 A i ? A j = N A_i * A_j = N Ai??Aj?=N,将 N N N分解质因数: p 1 a 1 ? p 2 a 2 ? . . . ? p k a k p_1^{a_1} * p_2^{a_2} * ... * p_k^{a_k} p1a1???p2a2???...?pkak??。
其中满足 a 1 , a 2 , . . . , a k a_1, a_2, ... ,a_k a1?,a2?,...,ak?都应是 K K K的倍数,这样才能均分给 K K K个 X X X。
对于一个 A j A_j Aj?: p 1 a 1 , p 2 a 2 , . . . , p 3 a k p_1^{a_1}, p_2^{a_2}, ... , p_3^{a_k} p1a1??,p2a2??,...,p3ak??(其中 a 1 , a 2 , . . . , a k a_1,a_2, ... , a_k a1?,a2?,...,ak?是对 K K K取模的余数),我们应找到 A i : p 1 K ? a 1 , p 2 K ? a 2 , . . . , p 3 K ? a k A_i : p_1^{K - a_1}, p_2^{K - a_2}, ... , p_3^{K - a_k} Ai?:p1K?a1??,p2K?a2??,...,p3K?ak??,的个数。
如何快速找到上述 A i A_i Ai?的个数,哈希,我们可以直接将 A x A_x Ax?: p 1 a 1 ? p 2 a 2 ? . . . ? p 3 a k p_1^{a_1}*p_2^{a_2}* ... * p_3^{a_k} p1a1???p2a2???...?p3ak??(其中 a 1 , a 2 , . . . , a k a_1,a_2, ... , a_k a1?,a2?,...,ak?是对 K K K取模的余数)作为哈希关键字,统计个数。
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;typedef long long LL;
const int N = 1e5 + 10;
int n, k;
int cnt[N];int power(int x, int b)
{
LL res = 1;while(b --) {
res *= x;if(res >= N) return 0;}return res;
}int main()
{
cin >> n >> k;LL ans = 0;while (n -- ){
int x;cin >> x;LL y = 1, z = 1;//y是x的哈希值,z是与x配对的哈希值。for(int i = 2; i * i <= x; i ++){
int s = 0;if(x % i == 0)while(x % i == 0) s ++, x /= i;s %= k;y *= power(i, s);z *= power(i, (k - s) % k);}if(x) y *= x, z *= power(x, k - 1);if(z >= N) z = 0;ans += cnt[z];if(y) cnt[y] ++;}cout << ans << endl;return 0;
}