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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章