codeforces1033D 2000分数学

题目传送门

题意:

给你\dpi{150} n个数,第\dpi{150}i个数是\dpi{150} a_i。令\dpi{150} sum = \prod _{i = 1} ^{n} a_i 。

\dpi{150} a_i\dpi{150} k_i个素数相乘得来,但输入只给出\dpi{150} a_i

\dpi{150} a_i约数的个数是\dpi{150} x ,则\dpi{150} x\in[3,5] 。

\dpi{150} k_i\in[2,4] 。

询问\dpi{150} sum的约数个数,答案取模。

数据范围:\dpi{150} 1\leqslant n\leqslant 500 , \dpi{150}1\leqslant a_i \leqslant 2 * 10^{18} 。

题解:

分析\dpi{150} a_i约数的个数\dpi{150} x  与  \dpi{150} k_i的关系,可以得知下列\dpi{150} 4种情况。

(1)\dpi{150} a_i = y ^ 4

(2)\dpi{150} a_i = y ^ 3

(3)\dpi{150} a_i = y ^ 2

(4)\dpi{150} a_i = x * y

\dpi{150} 3种情况开方判断即可。注意要结合\dpi{150} pow函数手动调精度。

通过最后一种情况之间的 \dpi{150} gcd 判定,可以得知素数的个数。

得到 \dpi{150} sum = \prod_{i=1}^{m} {p_i}^{c_i} ,其中\dpi{150} p_i是质数,你不需要知道\dpi{150} p_i是什么,但你需要知道\dpi{150} c_i

最后用 \dpi{150} \prod_{i = 1} ^{m} (c_i + 1) 计算约数个数,其中\dpi{150}\dpi{150}m\dpi{150} sum的质因子种类数,\dpi{150} c_i是第\dpi{150}i个质因子的个数。

感受:

被精度搞的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 ;
}
发布了215 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Irving0323/article/details/104096627
今日推荐