CF 222C-Reducing Fractions-素数分解与复位

Description

To confuse the opponents, the Galactic Empire represents fractions in an unusual format. The fractions are represented as two sets of integers. The product of numbers from the first set gives the fraction numerator, the product of numbers from the second set gives the fraction denominator. However, it turned out that the programs that work with fractions in this representations aren’t complete, they lack supporting the operation of reducing fractions. Implement this operation and the Empire won’t forget you.

Input

The first input line contains two space-separated integers n, m (1 ≤ n, m ≤ 105) that show how many numbers the first set (the numerator) and the second set (the denominator) contain, correspondingly.

The second line contains n space-separated integers: a1, a2, …, an (1 ≤ ai ≤ 107) — the numbers that are multiplied to produce the numerator.

The third line contains m space-separated integers: b1, b2, …, bm (1 ≤ bi ≤ 107) — the numbers that are multiplied to produce the denominator.

Output

Print the answer to the problem in the form, similar to the form of the input data. The number of values in the sets you print nout, mout must satisfy the inequality 1 ≤ nout, mout ≤ 105, and the actual values in the sets aout, i and bout, i must satisfy the inequality 1 ≤ aout,i , bout,i≤ 107.

Separate the values in the lines by spaces. The printed fraction must be reduced, that is, there mustn’t be such integer x (x > 1), that the numerator and the denominator of the printed fraction are divisible by x. If there are several matching answers, print any of them.

Sample Input

3 2
100 5 2
50 10

Sample Output

2 3
2 1
1 1 1

题目大意:

给定两行数,第一行n个数,它们的乘积作分子;第二行m个数,它们的乘积作分母。要求将分子分母中的公共因子全部消去后再以乘积的形式输出。

核心思想:

将素因子分成两部分处理:
小素数:1~1e4
大素数:1e4~1e7
欧拉线性筛出1e4以内的素数,将输入的每个整数素因子分解,则分解完毕后,剩下的整数为1或一个大素数。
一、小素数部分:
分子和分母的相同的素数抵消(个数相减)。
二、大素数部分:
先预处理分子,将分子中出现的大素数用map+vector进行存储。map<int,int>mp是大素数的数值向vector的映射,vectorvec[i]存储的是分子中第i个首次出现的大素数在分子中的所有位置
例如:分子是(下标从1开始) 9999991 1 9999991 1,那么mp[9999991]=1,vec[1]中存的是1,3。
然后遍历分母中的大素数(设其为su[i]),利用map二分查找分子中是否存在这个大素数,如果存在,则vec[mp[su[i]]]的元素个数-1(抵消一个相等的大素数),分母中的此位置被标记为1(表示此处的大素数被抵消,复原时无贡献)。

然后就是将素数复原到原来的位置,详见代码!

代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
const int N=1e4+50,M=1e5+50;
bool vis[N],booka[M],bookb[M];
vector<int>vec[M];//存大素数的位置
map<int,int>mp;//处理大素数,从数值向vec映射
int cv,len[M];//用于vector
int cnt,pre[N];//用于筛素数
int ca[N],cb[N];//ca[i]表示分子部分含素因子pre[i]的个数,cb[i]表示分母部分含素因子pre[i]的个数
int a[M],b[M],ta[M],tb[M];//存分子和分母的原数值,ta和tb是拷贝一份备用
int pa[M],pb[M];//用于输出
void xss()
{
    for(int i=2;i<N-30;i++)
    {
        if(!vis[i])
            pre[cnt++]=i;
        for(int j=0;j<cnt&&i*pre[j]<N-10;j++)
        {
            vis[i*pre[j]]=1;
            if(i%pre[j]==0)break;
        }
    }
    return;
}
//分解函数是将一个集合进行素数分解,集合元素个数为nf,集合为数组f,原数拷贝到数组tf中,素数pre[i]的个数记录在cf[i]中
void fenjie(int nf,int *f,int *tf,int *cf)
{
    for(int i=1;i<=nf;i++)
    {
        scanf("%d",&f[i]);
        tf[i]=f[i];
        for(int j=0;f[i]>1&&j<cnt;j++)
            while(f[i]%pre[j]==0)
            {
                cf[j]++;
                f[i]/=pre[j];
            }
    }
    return;
}
//fun函数是将素数复位到原位置上,便于输出
void fun(int nf,int *f,int *pf,int *tf,int *cf,bool *bookf)
{
    for(int i=1;i<=nf;i++)//复位大素数
        if(f[i]>1&&!bookf[i])
            pf[i]=f[i];
        else
            pf[i]=1;
    for(int i=0;i<cnt;i++)//复位小素数
    {
        for(int j=1;cf[i]&&j<=nf;j++)
        {
            while(tf[j]%pre[i]==0&&cf[i])
            {
                tf[j]/=pre[i];
                pf[j]*=pre[i];
                cf[i]--;
            }
        }
    }
    return;
}
int main()
{
    cv=1;
    xss();
    int n,m;
    cin>>n>>m;
    fenjie(n,a,ta,ca);//分解分子
    fenjie(m,b,tb,cb);//分解分母
    for(int i=0;i<cnt;i++)//分子和分母约去共有的小素数
    {
        int mx=min(ca[i],cb[i]);
        ca[i]-=mx;cb[i]-=mx;
    }
    //处理分子中的大素数
    for(int i=1;i<=n;i++)
    {
        if(a[i]==1)continue;
        int te=mp[a[i]];
        if(!te){//这个大素数在分子中首次出现
            vec[cv].push_back(i);
            mp[a[i]]=cv++;
        }
        else vec[te].push_back(i);//已经出现过
    }
    for(int i=1;i<cv;i++)//拷贝大素数每个数值的个数
        len[i]=vec[i].size();
    //根据分子中的大素数来处理分母中的大素数
    for(int i=1;i<=m;i++)
    {
        int te=mp[b[i]];
        if(!len[te])continue;//分母中大素数b[i](或1)无法被分子约去
        bookb[i]=1;
        len[te]--;
    }
    for(int i=1;i<cv;i++)
    {
        int en=vec[i].size();
        for(int j=len[i];j<en;j++)
            booka[vec[i][j]]=1;//分子上被分母约去的大素数的位置标记为1
    }
    fun(n,a,pa,ta,ca,booka);//分子复原
    fun(m,b,pb,tb,cb,bookb);//分母复原
    //输出
    printf("%d %d\n",n,m);
    for(int i=1;i<n;i++)
        printf("%d ",pa[i]);
    printf("%d\n",pa[n]);
    for(int i=1;i<m;i++)
        printf("%d ",pb[i]);
    printf("%d\n",pb[m]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章