AtCoderAGC003D Anticube

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;
}
posted @ 2018-09-04 06:50  ART_coder  阅读(288)  评论(0编辑  收藏  举报