题目大意
给定$N$个数,求一个最大的子集,使得任意两两的乘积不是一个完全立方数。
$nleq 10^5 A_ileq 10^{10}$
题解
考虑两两乘积为$x^3$,由于$x^3leq 10^{20}$,那么$xleq 10^{frac{20}{3}}$,那么$x$最多出现一个超过$10^{frac{10}{3}}$的质因子,且这一质因子不会超过$10^{frac{20}{3}}$。又由于$A_ileq 10^{10}$,所以至多出现一个$> 10^5$的质因子,由于$x^3$由两个$A_i$相乘,那么$x$一定不会出现超过$>10^5$的质因子。
所以$x$由$[2,10^5]$内的质数幂构成,且$[10^{frac{10}{3}},10^5]$内质数至多出现$1$个,且指数不超过$1$。
那么考虑筛出$10^5$以内的质数。
对于每一个$A_i$我们直接暴力枚举$<10^{frac{10}{3}}$的质数(大约$300$个左右),直接筛掉,过滤掉质数是$3$的倍数的质因子,记录它由哪几个剩下的质因子构成,并将它每一个质因子质数模$3$的余数($1$或$2$)压进一个二进制状态中。对于剩下的数,如果它不为$1$,我们判断它是不是一个$<10^5$的质数或者一个$<10^5$的质数的平方,如果不是,那么它一定无法和别的任何一个数组成立方数,因为它肯定是一个$>10^5$的质数。否则,我们直接把这个稍大的质数当做之前过滤的数一样压入状态中。
对于两个过滤完的质因子的集合完全相同的数,它们能组成立方数当且仅当它们的二进制状态是恰好相反的,这样就能凑出每一个质因子的质数都是$3$的倍数。
然后就可以直接按照质因子集合放在一起,记录每一种状态和它的补集包含的数的数量,选集合大小更大的那一堆即可。
复杂度$O(nlog n+300n)$。
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #define LL long long #define M 300020 #define MAXN 100000 using namespace std; int n,m,sz[M],K[M],res,mp[200002]; int od[M],ans; LL p[M],pri[M],t[M]; bool isp[M]; bool cmp(int x,int y){return t[x]<t[y];} LL read(){ LL nm=0; char cw=getchar(); for(;!isdigit(cw);cw=getchar()); for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0'); return nm; } int main(){ memset(isp,true,sizeof(isp)); for(int i=2;i<MAXN;i++){ if(!isp[i]) continue; pri[++m]=i; for(int j=(i<<1);j<MAXN;j+=i) isp[j]=false; } n=read(); for(int j,i=1;i<=n;i++){ for(p[i]=read(),K[i]=sz[i]=0,j=t[i]=1;j<=308;j++){ if(p[i]%pri[j]) continue; int cnt=0; while(!(p[i]%pri[j])) p[i]/=pri[j],++cnt; cnt%=3; if(cnt) K[i]|=((cnt&1)<<sz[i]),sz[i]++,t[i]*=pri[j]; } if(p[i]>1ll){ if(p[i]<MAXN) K[i]|=(1<<sz[i]),sz[i]++,t[i]*=p[i]; else { LL qq=sqrt(p[i]); if(qq*qq!=p[i]) ans++,i--,n--; else sz[i]++,t[i]*=qq; } } } for(int i=1;i<=n;i++) od[i]=i; sort(od+1,od+n+1,cmp); for(int l=1,r;l<=n;l=r+1){ for(r=l;r<n&&t[od[r]]==t[od[r+1]];r++); if(t[od[l]]==1){ans++;continue;} int maxn=(1<<sz[od[l]])-1; for(int i=l;i<=r;i++) mp[K[od[i]]]++; for(int i=l;i<=r;i++){ int x=K[od[i]],ot=(maxn^K[od[i]]); if(mp[x]>=mp[ot]) ans+=mp[x],mp[x]=mp[ot]=0; } } printf("%d ",ans); return 0; }