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;
}