题面
链接:https://ac.nowcoder.com/acm/contest/7604/C
牛牛的班级中有n个人,他们的性格各不相同。
牛牛现在想要从这n个人中选出一些人组成一个兴趣小组,但是他想让参加这个兴趣小组的人数尽可能的多。但是他有不想让其中有任何一对人之间由于性格问题产生矛盾。
具体来说,如果这个兴趣小组中出现两个人性格值的乘积开三次方根是一个正整数,就认为他们两个性格不合。
比如一个性格值为2的同学和一个性格值为4的同学就是性格不合的,因为2*4=8,而一个性格值为2的同学和一个性格值为8的同学性格相合,可以出现在同一个兴趣小组中,因为2*8=16,16开三次方根不是一个正整数。
请你告诉牛牛,他们班的同学组成的最大兴趣小组的人数是多少。
解法
贪心。
可以想到,对于后续操作来说,2和16是没有区别的,因为只要和2性格不合的数,一定和16性格不合。推而广之,如果a和b性格不合,那么如果\(c=\dfrac{a}{t^3},t\in N^+\),那么c一定和b性格不合。
所以可以先把每个元素里的立方数先剔除,然后再进行后续处理。
可以想到,分解之后的数a一定满足:
\(a=\prod{p_i^{c_i}},c_i\in\{1,2\}\),其中p为质数。
为什么指数一定是1或2呢?因为凡是大于3的都被剔除了。然后就可以想到如果b和a是性格不合的,那么b剔除立方数之后(假设为d)一定满足:
\(d=\prod{p_i^{3-c_i}}\),因为只有这样才能满足a和d相乘之后每个质因数的次数都是三的倍数。
很明显,对于任何一个a,有且仅有一个d与之对应。也就是说,a和d只能选一个,而且这个选择和其它任何选择没有关系。那肯定选多的(比如有3个a,2个d,那肯定选a,并把答案加上3)。
用map记录即可。
#include<cstdio>
#include<map>
#define int long long
//#define zczc
using namespace std;
const int N=100010;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<‘0‘||w>‘9‘){if(w==‘-‘)f=-1;w=getchar();}
while(w<=‘9‘&&w>=‘0‘){wh=wh*10+w-‘0‘;w=getchar(); }
wh*=f;return;
}
inline int max(int s1,int s2){
return s1<s2?s2:s1;
}
int m,a[N],b[N];
map<int,int>sum;
map<int,bool>vis;
inline void get(int wh,int data){
for(int i=2;;i++){
int nl=i*i*i;
if(nl>data)break;
while(data%nl==0)data/=nl;
}
a[wh]=data;
sum[data]++;
int now=1;
for(int i=2;i*i<=data;i++){
int nsum=0;
while(data%i==0)data/=i,nsum++;
if(nsum==1)now*=i*i;
if(nsum==2)now*=i;
}
if(data>1)now*=data*data;
b[wh]=now;
return;
}
signed main(){
#ifdef zczc
freopen("in.txt","r",stdin);
#endif
read(m);
int ans=0,in;
for(int i=1;i<=m;i++){
read(in);get(i,in);
}
for(int i=1;i<=m;i++){
if(vis[a[i]])continue;
if(a[i]==1)ans++;
else ans+=max(sum[b[i]],sum[a[i]]);
vis[a[i]]=vis[b[i]]=true;
}
printf("%lld\n",ans);
return 0;
}