4319. 合适数对
题目链接
4319. 合适数对
给定一个长度为 \(n\) 的正整数数列 \(a_{1}, a_{2}, \ldots, a_{n}\) 和一个正整数 \(k_{\text {。 }}\) 请你判断共有多少个数对 \((l, r)\) 同时满足:
- \(1 \leq l<r \leq n\)
- 存在一个整数 \(x\) 使得 \(a_{l} \times a_{r}=x^{k}\) 成立
输入格式
第一行包含两个整数 \(n, k_{\text {。 }}\)
第二行包含 \(n\) 个正整数 \(a_{1}, a_{2}, \ldots, a_{n}\) 。
输出格式
一个整数,表示满足条件的数对的数量。
数据范围
前三个测试点满足 \(2 \leq n \leq 10\) 。
所有测试点满足 \(2 \leq n \leq 10^{5} , 2 \leq k \leq 100 , 1 \leq a_{i} \leq 10^{5}\) 。
输入样例:
63
1398241
输出样例:
5
解题思路
算术基本定理
一个数可以表示为若干个素数幂次方乘积的形式,固定 \(a_r\),假设其表示为 \(p_1^{c_1}p_2^{c_2}\dots p_n^{c_n}\),如果存在 \(c_i\%k=0\),则不用管这个素数,因为如果前面存在该素数的幂次 \(c_j\%k\neq 0\),则这个数肯定不用统计到答案里面去,而如果前面存在该素数的幂次 \(c_j\%k= 0\),则由于没管这个素数,所以对答案的统计没有影响,而对于当前数 \(a_r\) 的一个素数的幂次 \(c_i\),要求找到这样的一种数:它的所有素数的幂次 \(c_j=k-c_i\%k\),而这样的数根据算术基本定理又是唯一的,可以直接根据值进行哈希
- 时间复杂度:\(O(nlogn)\)
代码
- 哈希
// Problem: 合适数对
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/4322/
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=1e5+5;
int n,k,a[N];
map<vector<PII>,int> mp;
LL res;
vector<PII> v,t;
void divide(int x)
{
for(int i=2;i<=x/i;i++)
if(x%i==0)
{
int c=0;
while(x%i==0)x/=i,c++;
if(c%k)v.pb({i,c%k}),t.pb({i,k-c%k});
}
if(x>1)v.pb({x,1}),t.pb({x,k-1});
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)
{
v.clear();
t.clear();
divide(a[i]);
res+=mp[t];
mp[v]++;
}
cout<<res;
return 0;
}
- 朴素分解质因数
// Problem: 合适数对
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/4322/
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=1e5+5;
int n,k,a[N];
int cnt[N],t,tt;
LL res;
void divide(int x)
{
t=1,tt=1;
for(int i=2;i<=x/i;i++)
if(x%i==0)
{
int c=0;
while(x%i==0)x/=i,c++;
c%=k;
if(c)
{
for(int j=0;j<c;j++)t*=i;
for(int j=0;j<k-c;j++)
{
if(1ll*tt*i>=N)
{
tt=0;
break;
}
tt*=i;
}
}
}
if(x>1)
{
t*=x;
for(int j=0;j<k-1;j++)
{
if(1ll*tt*x>=N)
{
tt=0;
break;
}
tt*=x;
}
}
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)
{
divide(a[i]);
res+=cnt[tt];
cnt[t]++;
}
cout<<res;
return 0;
}
- 欧拉分解质因数
// Problem: 合适数对
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/4322/
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=1e5+5;
int n,k,a[N];
int cnt[N],t,tt;
LL res;
int prime[N],m,v[N];
void primes(int n)
{
for(int i=2;i<=n;i++)
{
if(!v[i])v[i]=i,prime[++m]=i;
for(int j=1;j<=m;j++)
{
if(prime[j]>n/i||v[i]<prime[j])break;
v[i*prime[j]]=prime[j];
}
}
}
void divide(int x)
{
int lst=0,cnt=0;
t=1,tt=1;
while(x!=1)
{
if(lst==0)cnt=1;
else if(v[x]==lst)cnt++;
else
{
if(cnt%k)
{
for(int i=0;i<cnt%k;i++)t*=lst;
for(int i=0;i<k-cnt%k;i++)
{
if(1ll*tt*lst>=N)
{
tt=0;
break;
}
tt*=lst;
}
}
cnt=1;
}
lst=v[x],x/=v[x];
}
if(cnt%k)
{
for(int i=0;i<cnt%k;i++)t*=lst;
for(int i=0;i<k-cnt%k;i++)
{
if(1ll*tt*lst>=N)
{
tt=0;
break;
}
tt*=lst;
}
}
}
int main()
{
cin>>n>>k;
primes(N-1);
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)
{
divide(a[i]);
res+=cnt[tt];
cnt[t]++;
}
cout<<res;
return 0;
}