题目链接:
题目大意:
给出两个集合,第一个集合数的乘积是分子,第二个集合的数的乘积是分母,要求够造一个同样的集合,但是得到的分数是化简过的。
题目分析:
-首先筛出素数,然后处理每一集合,统计每个集合的各个质因数出现的次数,然后每个质因数减去两个集合较小的那个的质因数的个数,然后利用每个集合约分后剩下的质因数构造出合法解即可,采用的对于每个数,贪心的除去被约分掉的部分。
- 筛取质因数不能采用(√n)的方法会超时,构造时也不行,有一些利用数的性质的小的优化。
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define MAX 100007
using namespace std;
typedef long long LL;
int a[MAX],b[MAX],n,m,mark[MAX*100];
int num1[MAX*100],num2[MAX*100];
void init ( )
{
memset ( mark , 0, sizeof ( mark ) );
mark[1] = mark[0] = 1;
LL lim = 1e7;
for ( LL i = 2 ; i <= lim; i++ )
{
if ( mark[i] ) continue;
for ( LL j = i*i ; j <= lim; j+=i )
{
mark[j] = 1;
}
}
}
void _handle ( int num , int cnt[] )
{
for ( int i = 2 ; i*i <= num &&mark[num];i++)
while ( num%i == 0 )
{
cnt[i]++;
num /= i;
}
if ( num > 1 ) cnt[num]++;
}
int _make ( int num , int cnt[])
{
int ret = 1;
for ( int i = 2 ; i*i <= num && mark[num];i++)
while ( num%i == 0 )
{
if ( cnt[i] )
{
cnt[i]--;
ret *= i;
}
num /= i;
}
if ( num > 1 && cnt[num] )
{
cnt[num]--;
ret *= num;
}
return ret;
}
int main ( )
{
init ( );
while ( ~scanf ( "%d%d" , &n , &m ) )
{
memset ( num1 , 0 , sizeof ( num1 ) );
memset ( num2 , 0 , sizeof ( num2 ) );
int maxn = 0;
for ( int i = 0 ; i < n ; i++ )
{
scanf ( "%d" , &a[i] );
_handle ( a[i] , num1 );
maxn = max ( a[i] , maxn );
}
for ( int i = 0 ; i < m ; i++ )
{
scanf ( "%d" , &b[i] );
_handle ( b[i] , num2 );
maxn = max ( b[i] , maxn );
}
for ( int i = 0 ; i <= maxn ; i++ )
{
int temp = min ( num1[i] , num2[i] );
num1[i] -= temp;
num2[i] -= temp;
}
printf ( "%d %d\n" , n , m );
for ( int i = 0 ; i < n ; i++ )
printf ( "%d " , _make ( a[i] , num1 ) );
puts ("");
for ( int i = 0 ; i < m ; i++ )
printf ( "%d " , _make ( b[i] , num2 ) );
puts ("");
}
}