[题解]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;
}
浙公网安备 33010602011771号