[题解]CF1033D Divisors

CF1033D Divisors

如果直接质因数分解,单个元素的时间消耗将达到\(O(\sqrt{a_i})\),显然过不掉。

虽然可以通过Pollard-rho算法在\(O(\sqrt{p})\)\(p\)\(a_i\)的最大质因数)的期望复杂度完成因数分解,但是似乎会被卡。

我们从题面“\(a_i\)的因数个数在\(3\)\(5\)之间”这个条件入手。

根据因数个数定理,我们可以得知:

  • \(a_i\)\(3\)个因数,则\(a_i\)是某个质数的平方。
  • \(a_i\)\(4\)个因数,则\(a_i\)是某个质数的立方,或是两个质数的乘积。
  • \(a_i\)\(5\)个因数,则\(a_i\)是某个质数的\(4\)次方。

如果我们将每个质因数出现次数记下来,就可以直接用因数个数定理求解。

其中“只有一个质因子”的情况,直接二分计算\(2/3/4\)次方根,进而判断是否为完全\(2/3/4\)次方数就可以了。

对于“两个质数的乘积”,处理起来或许有些棘手?

我们将这些数字去重,并存在数组\(v\)中,将\(v\)中每个数字出现次数记为\(d\)

考虑什么情况下,我们可以得知其中的一些质数。

显然就是当两个数的\(\gcd\)\(\neq 1\)时,则这个\(\gcd\)值一定是其中的某个质数。于是我们将这些\(\gcd\)值与前面分解出的质数放在一起统计。

而对于那些求不出来的质数,它们一定恰好\(v\)\(1\)个元素的质因数。也就是说,作为一个质因数,它的指数是\(d\),这个单独统计即可。

用到的思想就是,没有必要求出所有的所有的质数,我们只关心它们的出现次数而已~

时间复杂度\(O(n^2)\)

点击查看代码 #330522929
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=514,P=998244353;
int n,a[N],ans=1;
unordered_map<int,int> ma,cnt;
vector<int> v;
int sq2(int x){
	int l=0,r=2e9,m;
	while(l<r) m=(l+r)>>1,(m*m<x?l=m+1:r=m);
	return l;
}
int sq3(int x){
	int l=0,r=2e6,m;
	while(l<r) m=(l+r)>>1,(m*m*m<x?l=m+1:r=m);
	return l;
}
int sq4(int x){
	int l=0,r=4e4,m;
	while(l<r) m=(l+r)>>1,(m*m*m*m<x?l=m+1:r=m);
	return l;
}
signed main(){
	cin>>n;
	for(int i=1,t;i<=n;i++){
		cin>>a[i];
		if(t=sq4(a[i]),t*t*t*t==a[i]) ma[t]+=4;//4要在2前面判
		else if(t=sq2(a[i]),t*t==a[i]) ma[t]+=2;
		else if(t=sq3(a[i]),t*t*t==a[i]) ma[t]+=3;
		else{
			if(!cnt[a[i]]) v.emplace_back(a[i]);
			cnt[a[i]]++;
		}
	}
	int g;
	for(int i:v){
		for(int j:v){
			if(i==j) break;
			if((g=__gcd(i,j))!=1&&!ma.count(g)) ma[g]=0;
		}
	}
	for(int i:v){
		int c=2,d=cnt[i];
		for(auto &j:ma) if(i%j.first==0) j.second+=d,c--;
		(ans*=(c==1?(d+1):(c==2?(d+1)*(d+1):1)))%=P;
	}
	for(auto i:ma) (ans*=(i.second+1))%=P;
	cout<<ans<<"\n";
	return 0;
}
posted @ 2025-07-23 22:06  Sinktank  阅读(21)  评论(0)    收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2025 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.