求乘积为立方数的数对个数。(不考虑数对中数的相对顺序)
先筛掉每个原数中的立方因子得到新数,对于每一个新数,若存在平方因子,则需要找该平方因子为1的对应的数与其匹配;若不存在平方因子(即只含单个因子),则找含有两个该单因子的数与其匹配。
注意,找到的匹配的数可能会超过1e^6,此时需要判断一下,并且用long long来存储,否则会RE。
具体代码实现的时候,使用一个变量tem,记录当前的数所含素因子的情况,即每次把当前的数所含的平方因子、单个因子都用tem累乘起来。该tem的个数加1。这样下一个数找对应匹配的数的时候,只要累加之前已经出现过的对应匹配的数的个数就可以了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<stack>
#include<vector>
using namespace std;
typedef long long LL;
bool vis[1005];
int prim[1005],tot,cnt[1000005];
void init()
{
for(int i=2;i<=1000;++i){
if(!vis[i]) prim[tot++]=i;
for(int j=0;j<tot&&i*prim[j]<=1000;++j){
vis[prim[j]*i]=1;
if(i%prim[j]==0) break;
}
}
}
int main()
{
init();
int t,n,x,i,j;
cin>>t;
while(t--)
{
scanf("%d",&n);
int ans=0;
memset(cnt,0,sizeof(cnt));
for(i=1;i<=n;++i)
{
bool flag=1;
LL p=1;
int tem=1;
scanf("%d",&x);
for(j=0;j<tot&&prim[j]<=x;++j){
int y=prim[j]*prim[j]*prim[j];
while(x%y==0) x/=y;
if(x%(prim[j]*prim[j])==0){
x/=(prim[j]*prim[j]);
tem=tem*prim[j]*prim[j];
if(flag) p*=prim[j];
}else if(x%prim[j]==0){
x/=prim[j];
tem*=prim[j];
if(flag) p=p*prim[j]*prim[j];
}
if(p>1000000) flag=0;
}
if(flag){
if(x!=1) p=p*x*x;
if(p<=1000000) ans+=cnt[p];
}
if(x!=1) tem*=x;
cnt[tem]++;
}
printf("%d\n",ans);
}
return 0;
}