CF1823C Strongly Composite

发布时间 2023-08-27 10:43:19作者: One_JuRuo

思路

我们可以思考一下什么样子的合数是强合数。

首先一个数可以表示为 \(p_1^{c_1}\times p_2^{c_2}\times \cdots \times p_x^{c_x}\)

那么这个数的约数个数为 \(s=(c_1+1)\times (c_2+1)\times \cdots \times (c_x+1)\)。那么,我们可以根据 \(s\) 初步排除一部分强合数:

  • \(s=1\),则原数是 \(1\),不可能为强合数。

  • \(s=2\),则原数是质数,不可能为强合数。

所以如果 \(s\le2\),则该数不可能为强合数。

再令质数的个数为 \(x\),则合数的个数为 \(s-x-1\)

所以只要 \(x\le s-x-1\Rightarrow 2\times x\le s-1\),这个数就是强合数。

若一个数是强合数,我们考虑给它乘以若干个互不相同且之前没出现过的质数,假设质数的数量为 \(k\)

那么只要 \(2\times(x+k)\le s\times 2^k -1\) 乘以这些质数后就还是强合数。

即需要证明 \(2\times k\le s\times (2^k-1)\)

因为原数是强合数,所以 \(s\ge 3\)

易知,\(k=1\) 时,一定满足条件,因为左侧是线性增长,右侧是指数增长,所以后续右侧一定会越来越比左侧大。

所以强合数乘以若干个互不相同且不是原数的质因数的质数,无论乘以多少个,它还是强合数。

再思考,如果乘以了已经存在过的质数,那么质数因数不会变,合数因数会变多,所以还是强合数。

综合一下,就是强合数乘以任意正整数后还是强合数。

再来思考,至少存在几个质因数可以成为强合数。

首先是只有一种质因数,如果只有一个,那原数就是质数,不可能为强合数;如果超过一个,那就是上面的 \(s=2\) 的情况,是强合数。

然后是至少有几个不同的质因数,令有 \(x\) 个不同的质因数,那么共有 \(2^x\) 个因数,有 \(2^x-x-1\) 个合数因数。

如果原数是强合数,那么 \(x\le 2^x-x+1\)\(2^x-2\times x-1\ge 0\),发现当且仅当 \(x\ge 3\) 时,原数是强合数。

因为一个强合数乘以任意一个正整数后还是强合数,所以只要这个数有一个质因数的个数大于等于 \(2\) 或者有至少 \(3\) 个质因数时是强合数。

因为前一种所需的最少质因数比后一种所需的最少质因数还要少,所以我们尽量先多造前一种强合数,再造后一种强合数

现在给定了 \(a_i\) 就代表 \(\prod_{i}^n a_i\) 是定值,然后对其进行质因数分解。对于所有的质因数,令其个数为 \(cnt\),如果 \(cnt>1\),那么这些质因子可以造出 \(\lfloor \frac{cnt}2\rfloor\) 个强合数,如果 \(cnt\) 是奇数,那么就会剩下一个质因数。

剩下的质因数可以三个一对造强合数,剩下的质因数就随便乘给任意数即可。

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);
	}
}