#线性筛,哈希#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);
}