题目传送门
题意:
给你个数,第个数是。令 。
由个素数相乘得来,但输入只给出。
设约数的个数是 ,则 。
。
询问的约数个数,答案取模。
数据范围: , 。
题解:
分析约数的个数 与 的关系,可以得知下列种情况。
(1)
(2)
(3)
(4)
前种情况开方判断即可。注意要结合函数手动调精度。
通过最后一种情况之间的 判定,可以得知素数的个数。
得到 ,其中是质数,你不需要知道是什么,但你需要知道。
最后用 计算约数个数,其中是的质因子种类数,是第个质因子的个数。
感受:
被精度搞的WA了几发,学会了手动调整精度的姿势。
代码写的极其混乱,是这道题的其他博客代码长度的2~3倍。
代码:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const ll mod = 998244353 ;
const int maxn = 1e4 + 5 ;
const double eps = 1e-6 ;
int n ;
int cnt = 0 , cur = 0 ;
ll ans = 1 ;
struct node
{
ll x , num ;
} a[maxn] ;
struct prime
{
ll x , num ;
} p[maxn] ;
ll four(ll x)
{
ll y = pow(x , 1.0 / 4) + eps ;
if(y * y * y * y == x)
{
bool flag = 0 ;
for(int i = 1 ; i <= cnt ; i ++)
if(y == p[i].x){flag = 1 , p[i].num += 4 ; break ;}
if(!flag) p[++ cnt].x = y , p[cnt].num = 4 ;
return 1 ;
}
y ++ ;
if(y * y * y * y == x)
{
bool flag = 0 ;
for(int i = 1 ; i <= cnt ; i ++)
if(y == p[i].x){flag = 1 , p[i].num += 4 ; break ;}
if(!flag) p[++ cnt].x = y , p[cnt].num = 4 ;
return 1 ;
}
return 0 ;
}
ll three(ll x)
{
ll y = pow(x , 1.0 / 3) + eps ;
if(y * y * y == x)
{
bool flag = 0 ;
for(int i = 1 ; i <= cnt ; i ++)
if(y == p[i].x){flag = 1 , p[i].num += 3 ; break ;}
if(!flag) p[++ cnt].x = y , p[cnt].num = 3 ;
return 1 ;
}
return 0 ;
}
ll two(ll x)
{
ll y = pow(x , 1.0 / 2) + eps ;
if(y * y == x)
{
bool flag = 0 ;
for(int i = 1 ; i <= cnt ; i ++)
if(y == p[i].x){flag = 1 , p[i].num += 2 ; break ;}
if(!flag) p[++ cnt].x = y , p[cnt].num = 2 ;
return 1 ;
}
return 0 ;
}
void add_a(ll x , ll num)
{
bool flag = 0 ;
for(int i = 1 ; i <= cur ; i ++)
if(x == a[i].x)
{
flag = 1 ;
a[i].num += num ;
break ;
}
if(!flag) a[++ cur].x = x , a[cur].num = num ;
}
void add_p(ll x , ll num)
{
bool flag = 0 ;
for(int i = 1 ; i <= cnt ; i ++)
if(x == p[i].x)
{
flag = 1 ;
p[i].num += num ;
break ;
}
if(!flag) p[++ cnt].x = x , p[cnt].num += num ;
}
void try1(int i)
{
bool flag = 0 ;
for(int j = i + 1 ; j <= cur ; j ++)
{
ll y = __gcd(a[i].x , a[j].x) ;
if(y > 1)
{
flag = 1 ;
add_p(y , a[i].num) ;
add_p(a[i].x / y , a[i].num) ;
break ;
}
}
if(!flag)
{
ans *= (a[i].num + 1) , ans %= mod ;
ans *= (a[i].num + 1) , ans %= mod ;
}
}
void solve()
{
for(int i = 1 ; i <= cur ; i ++)
{
bool flag = 0 ;
for(int j = 1 ; j <= cnt ; j ++)
if(a[i].x % p[j].x == 0)
{add_p(p[j].x , a[i].num) , add_p(a[i].x / p[j].x , a[i].num) , flag = 1 ; break ;}
if(!flag) try1(i) ;
}
}
void cal()
{
for(int i = 1 ; i <= cnt ; i ++)
ans *= (p[i].num + 1) , ans %= mod ;
printf("%lld\n" , ans) ;
}
int main()
{
scanf("%d" , &n) ;
for(int i = 1 ; i <= n ; i ++)
{
ll x ;
scanf("%lld" , &x) ;
if(four(x)) continue ;
else if(three(x)) continue ;
else if(two(x)) continue ;
else add_a(x , 1) ;
}
solve() ;
cal() ;
return 0 ;
}