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;
}
posted @ 2022-03-27 20:06  zyy2001  阅读(19)  评论(0编辑  收藏  举报