codeforces222C 2000分数学

题目传送门

题意:

n个数的序列a,m个数的序列b。

序列a的乘积作为分子,序列b的乘积作为分母。

输出一个c序列和d序列。

序列c的乘积作为分子,序列d的乘积作为分母。是序列a和序列b表示的分数的约分形式。

输出的序列长度不超过 10^5 , 每个数的大小不超过 10^7

数据范围:1 \leqslant n , m \leqslant 10^5 , 1 \leqslant a_i , b_i \leqslant 10^7 。

题解:

因为输出的方案有个数限制和数值限制,所以很难构造。

考虑将原数除质因子的方式。

唯一分解定理计算分子的各个质因子的个数,分母的各个质因子的个数。

然后你可以知道约分后分子和分母中各个质因子的个数。

然后就可以知道每个数的质因子是否需要去掉。

感受:

题目讲的很不清楚,看了题解的翻译才懂。

其实所用空间可以更小,但是会多加一些判断。

代码:

#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 1e5 + 5 ;
const int maxm = 7e5 + 5 ;
const int inf = 1e7 ;
int n , m ;
int a[maxn] , b[maxn] ;
//int c[10000000] ;
int cnt = 0 ;
bool vis[inf + 5] ;
int prime[maxm] ;
int num[inf + 5][2] ;
int sum[inf + 5][2] ;
vector<int> v[maxn][2] ;
void get_prime()
{
   memset(vis , 0 , sizeof(vis)) ;
   vis[1] = 1 ;
   for(int i = 2 ; i <= inf ; i ++)
   {
     if(!vis[i]) 
     prime[++ cnt] = i ;
     for(int j = 1 ; j <= cnt && i * prime[j] <= inf ; j ++)
     {
       vis[i * prime[j]] = 1 ;
       if(i % prime[j] == 0) break ;
     }
   }
}
void init(int e , int x , int id)
{
	for(int i = 1 ; i <= cnt && prime[i] * prime[i] <= x ; i ++)
	{
		while(x % prime[i] == 0)
		{
			num[prime[i]][id] ++ ;
			x /= prime[i] ;
			v[e][id].push_back(prime[i]) ;
		}
	}
	if(x > 1)  num[x][id] ++ , v[e][id].push_back(x) ;
}
int cal(int e , int id)
{
	int ans = 1 ;
	for(auto x : v[e][id])
	  if(sum[x][id] > num[x][id])  sum[x][id] -- , ans *= x ;
	return ans ;
}
void solve()
{
	for(int i = 1 ; i <= cnt ; i ++)
	{
		int x = prime[i] ;
		if(num[x][0] == num[x][1])  num[x][0] = num[x][1] = 0 ;
		else if(num[x][0] < num[x][1])  
		  num[x][1] -= num[x][0] , num[x][0] = 0 ;  
		else if(num[x][0] > num[x][1])  
		  num[x][0] -= num[x][1] , num[x][1] = 0 ;  
	}
	for(int i = 1 ; i <= n ; i ++) 
	  a[i] /= cal(i , 0) ;
	for(int i = 1 ; i <= m ; i ++) 
	  b[i] /= cal(i , 1) ;
}
int main()
{
	scanf("%d%d" , &n , &m) ;
	for(int i = 1 ; i <= n ; i ++)  scanf("%d" , &a[i]) ;
	for(int i = 1 ; i <= m ; i ++)  scanf("%d" , &b[i]) ;
	get_prime() ;
	memset(num , 0 , sizeof(num)) ;
	for(int i = 1 ; i <= n ; i ++) init(i , a[i] , 0) ;
	for(int i = 1 ; i <= m ; i ++) init(i , b[i] , 1) ;
	memcpy(sum , num , sizeof(num)) ;
	solve() ;
	printf("%d %d\n" , n , m) ;
	for(int i = 1 ; i <= n ; i ++)  printf("%d " , a[i]) ;
	printf("\n") ;
	for(int i = 1 ; i <= m ; i ++)  printf("%d " , b[i]) ;
	printf("\n") ;
	return 0 ;
}

发布了215 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

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