CF1823C Strongly Composite
思路
我们可以思考一下什么样子的合数是强合数。
首先一个数可以表示为
那么这个数的约数个数为
-
若
s=1 ,则原数是1 ,不可能为强合数。 -
若
s=2 ,则原数是质数,不可能为强合数。
所以如果
再令质数的个数为
所以只要
若一个数是强合数,我们考虑给它乘以若干个互不相同且之前没出现过的质数,假设质数的数量为
那么只要
即需要证明
因为原数是强合数,所以
易知,
所以强合数乘以若干个互不相同且不是原数的质因数的质数,无论乘以多少个,它还是强合数。
再思考,如果乘以了已经存在过的质数,那么质数因数不会变,合数因数会变多,所以还是强合数。
综合一下,就是强合数乘以任意正整数后还是强合数。
再来思考,至少存在几个质因数可以成为强合数。
首先是只有一种质因数,如果只有一个,那原数就是质数,不可能为强合数;如果超过一个,那就是上面的
然后是至少有几个不同的质因数,令有
如果原数是强合数,那么
因为一个强合数乘以任意一个正整数后还是强合数,所以只要这个数有一个质因数的个数大于等于
因为前一种所需的最少质因数比后一种所需的最少质因数还要少,所以我们尽量先多造前一种强合数,再造后一种强合数
现在给定了
剩下的质因数可以三个一对造强合数,剩下的质因数就随便乘给任意数即可。
AC code
#include<bits/stdc++.h>
using namespace std;
int shu[10000005],pri[10000005],minp[10000005],cnt;
int T,n,a,b[10000005],num,siz;
map<int,int>m;
inline void init()//提前线性筛预处理每个数的最小质因数
{
for(int i=2;i<=10000000;++i)
{
if(!shu[i]) pri[++cnt]=i,minp[i]=i;
for(int j=1;j<=cnt&&pri[j]*i<=10000000;++j)
{
minp[pri[j]*i]=pri[j],shu[pri[j]*i]=1;
if(i%pri[j]==0) break;
}
}
}
inline void calc(int x)//除以最小质因数,较为快速地分解质因数
{
while(minp[x]>1) ++m[minp[x]],x/=minp[x];
if(x>1) ++m[x];
}
int main()
{
init();
scanf("%d",&T);
while(T--)
{
scanf("%d",&n),m.clear(),cnt=siz=0;
for(int i=1;i<=n;++i) scanf("%d",&a),calc(a);//乘起来在质因数分解,和每个数质因数分解,再把相同质数的指数相加是等效的,并且乘起来会导致数太多,线性筛没法预处理那么多,还可能会爆unsigned long long导致没有类型可以存
for(auto i:m)//遍历所有的质因数
{
cnt+=i.second/2;
if(i.second%2) ++siz;//统计剩下的质因数个数
}
cnt+=siz/3;
printf("%d\n",cnt);
}
}