[agc003d]Anticube

前言

简单贪心,最难的部分居然是分解质因数。

题目大意

从一个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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值