前言
简单贪心,最难的部分居然是分解质因数。
题目大意
从一个10^10的数列里选出最多的数,使两两乘积不为立方数。
做法
把每个数最简表示,即每个质因数的指数都模3。
还要求出这个最简数的补数,也就是满足最简的与其乘积为立方数的数。
对于数列中一个数集团和它的补数集团,贪心的选择较大的那个。
如果一个数和其补数相等,则只能选1个。
重点是求最简数以及补数。
枚举10103内的质数先筛掉,求出这种情况下的最简数及补数。
接下来剩下的数分解质因数最多两项,判断其是否为完全平方数即可。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
map<ll,int> s;
map<ll,bool> h;
const int maxn=100000+10,maxd=2200;
int id[maxn],pri[maxn],f[maxn],p[maxn][2],sta[maxn];
ll a[maxn],b[maxn];
bool bz[maxn];
int i,j,l,n,m,tot,top,cnt,ans,ca;
ll k,t;
int main(){
fo(i,2,maxn-10){
if (!bz[i]) pri[++top]=i,f[i]=i;
fo(j,1,top){
if ((ll)i*pri[j]>maxn-10) break;
bz[i*pri[j]]=1;
f[i*pri[j]]=pri[j];
if (i%pri[j]==0) break;
}
}
scanf("%d",&n);
fo(i,1,n){
scanf("%lld",&a[i]);
k=a[i];
a[i]=b[i]=1;
fo(j,2,maxd){
if (k==1) break;
if (bz[j]) continue;
t=(ll)j*j*j;
while (k%t==0) k/=t;
t=j*j;
if (k%t==0){
a[i]*=t;
b[i]*=j;
}
else if (k%j==0){
a[i]*=j;
b[i]*=t;
}
while (k%j==0) k/=j;
}
if (k>1){
t=ll(sqrt(k));
if (t*t==k){
a[i]*=k;
b[i]*=t;
}
else{
a[i]*=k;
b[i]*=k*k;
}
}
}
fo(i,1,n) s[a[i]]++;
fo(i,1,n)
if (!h[a[i]]){
h[a[i]]=1;
if (a[i]==b[i]) ans++;
else{
ans+=max(s[a[i]],s[b[i]]);
h[b[i]]=1;
}
}
/*ca=20;
fo(i,1,n) id[i]=i;
while (ca--){
random_shuffle(id+1,id+n+1);
tot=0;
fo(i,1,n)
if (!s[b[id[i]]]){
sta[++tot]=id[i];
s[a[id[i]]]=1;
}
ans=max(ans,tot);
fo(i,1,tot) s[a[sta[i]]]=0;
}*/
printf("%d\n",ans);
}