传送门:SDUT 3257
题目大意:
给你 n 个数,问你有几对数的乘积是立方数。
思路:
一开始我想通过打出立方数表做,但是两个的乘积最大是 1e12,所以要打 1e4 的表,而不是 1e2 的表……会超时。
其实在上一题 Square Number 的基础上就比较好做了。我们知道任意一个整数都可以唯一的表示成若干个素数的乘积的形式。所以一个立方数的所有质因子的质数都为 3 的倍数。
我们通过分解质因数得到每个数要想变成立方数需要乘以多少(记为 y),而自己剔除所有质因子的 3 次方后剩多少(记为 x)。
当前数可以跟之前所有剔除所有质因子的 3 次方后剩 y 的数构成一对,剔除所有质因子的 3 次方后剩 y 的数又会多一个。
注意:
在分解质因数时随时判断当前数是否为素数或 1,并及时跳出循环会节约时间。
代码:
#include<bits/stdc++.h>
typedef long long LL;
int vis[1000010];
int tol,pri[1000010],p[80000];
void init()
{ //素数打表
int i,j;
tol=0;
memset(pri,1,sizeof(pri));
for(i=2;i<1000010;i++)
if(pri[i])
{
p[tol++]=i;
for(j=2*i;j<1000010;j+=i) pri[j]=0;
}
}
int main()
{
int i,j,t,n,a,cnt;
LL x,y,ans;
init();
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
ans=0;
memset(vis,0,sizeof(vis));
for(i=0;i<n;i++)
{
scanf("%d",&a);
x=y=1;
for(j=0;j<tol;j++)
{//分解质因子
cnt=0; //当前质因子的个数
while(a%p[j]==0)
{
a/=p[j];
cnt++;
}
if(cnt%3==1)
{ //如果当前质因子个数 %3为1
x*=p[j]; //多的
y*=(LL)p[j]*p[j]; //需要的
}
else if(cnt%3==2)
{
x*=p[j]*p[j]; //多的
y*=(LL)p[j]; //需要的
}
if(pri[a]||a==1) break; //提高速度
}
if(a>1)
{ //如果 a是素数
x*=a;
y*=(LL)a*a;
}
if(y<1000005) ans+=vis[y]; //当前数与之前所有的数可以形成一对
vis[x]++;
}
printf("%lld\n",ans);
}
return 0;
}