Description:
给定一个序列\(a\),要求选出最多的序列元素并保证两两元素的乘积不为立方数
Solution:
我们考虑哪些因子是有用的,如果一个因子的指数\(>3\),我们可以将他化简为\(\text{%3}\)后的指数,这样不影响他找对应的不能一起选的,那我们先将所有数化简并分类(map一下),找出他们的补数(不能一起选的数),然后贪心的选择最大的,这一步需要质因数分解,但是\(10^{10}\)太大了,其实我们只用分解\(10^{\frac{10}{3}}\),剩下的因子只有几种情况,<1>只剩一个因子,<2>剩下两个因子,可能是完全平方数也可能不是,这些情况我们均可确定简数以及补数。注意:如果一个数与他的补数相等,我们只能选一个
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<map>
using namespace std;
const int MAXX=3000;
const int MAXN=100010;
map<long long ,int >num;
map<long long ,bool >vis;
int prime[MAXN],v[MAXN];
int n,tot,ans;
long long a[MAXN],b[MAXN];
inline void init(){
for(int i=2;i<=MAXX;++i){
if(!v[i]){
prime[++tot]=i;
v[i]=i;
}
for(int j=1;j<=tot;++j){
if(i*prime[j]>MAXX||v[i]<prime[j])break;
v[i*prime[j]]=prime[j];
}
}
}
inline void solve(long long x,int pos){
long long u=1;
long long v=1;
for(int i=1;i<=tot;++i){
if(x%prime[i]==0){
long long cnt=0;
while(x%prime[i]==0){
x/=prime[i];
cnt++;
}
cnt%=3;
if(cnt==1){
u*=prime[i];
v*=prime[i]*prime[i];
}
if(cnt==2){
u*=prime[i]*prime[i];
v*=prime[i];
}
}
if(x==1)break;
}
if(x>1){
long long t=(long long)sqrt(x);
u*=x;
if((t*t)==x)v*=t;
else v*=x*x;
}
a[pos]=u;
b[pos]=v;
num[u]++;
}
int main(){
init();
scanf("%d",&n);
for(int i=1;i<=n;++i)cin>>a[i];
for(int i=1;i<=n;++i)solve(a[i],i);
for(int i=1;i<=n;++i){
if(!vis[a[i]]){
vis[a[i]]=1;
vis[b[i]]=1;
if(a[i]==b[i])ans++;
else ans+=max(num[a[i]],num[b[i]]);
}
}
cout<<ans<<endl;
return 0;
}