#线性筛,哈希#CF1225D Power Products

题目

给定一个长度为 \(n\) 的正整数序列 \(a\),问有多少对 \((i,j),i<j\) 使得存在一个整数 \(x\) 满足 \(a_i\times a_j=x^k\)


分析

\(a_i\) 分解质因数可以发现,其实是要满足对于每个质因数的指数之和 \(c_i+c_j\)\(k\) 的倍数

那么先将 \(10^5\) 以内的质数找出来,然后对于每个数求出指数模 \(k\) 的余数, 将其用字符串哈希压缩,然后求互补的对数就可以了


代码

#include <cstdio>
#include <cctype>
#include <map>
using namespace std;
typedef unsigned long long ull;
const int N=100011; map<ull,int>uk;
int v[N],prime[N],a[N],n,mx,Cnt,k; ull p[N],ans;
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
void Pro(int n){
	v[1]=-1;
	for (int i=2;i<=n;++i){
		if (!v[i]) prime[++Cnt]=i,v[i]=Cnt;
		for (int j=1;prime[j]<=n/i&&j<=Cnt;++j){
			v[i*prime[j]]=j;
			if (i%prime[j]==0) break;
		}
	}
}
int max(int a,int b){return a>b?a:b;}
int main(){
	n=iut(),k=iut(),p[0]=1;
	for (int i=1;i<=n;++i){
		a[i]=iut();
		mx=max(mx,a[i]);
	}
	Pro(mx);
	for (int i=1;i<=Cnt;++i) p[i]=p[i-1]*5623;
	for (int i=1;i<=n;++i){
		ull t0=0,t1=0;
		for (int j=1;j<=Cnt&&prime[j]<=a[i]/prime[j];++j)
		if (a[i]%prime[j]==0){
			int t=0;
			while (a[i]%prime[j]==0)
			    a[i]/=prime[j],++t;
			if ((t%=k)==0) continue;
			t0+=p[j]*t,t1+=p[j]*(k-t);
		}
		if (a[i]>1) t0+=p[v[a[i]]],t1+=p[v[a[i]]]*(k-1);
		ans+=uk[t1],++uk[t0];
	}
	return !printf("%llu",ans);
}
posted @ 2023-07-24 00:00  lemondinosaur  阅读(7)  评论(0编辑  收藏  举报