Codeforces 582A GCD Table

题意:有个长度为n(1 <= n <= 500)的序列(ai <= 1e9),然后这个序列两两元素之间的GCD可以构成一个表,比如对于序列{4, 3, 6, 2}就能构成下面的GCD表

问题就是,给你一个GCD表中的所有数字(无序的),然后根据这些数字把原序列反推出来

Examples
---------------------
input
4
2 1 2 3 4 3 2 6 1 1 2 2 1 2 3 2
output
4 3 6 2
-----------
input
1
42
output
42 
-----------
input
2
1 1 1 1
output
1 1 

原题链接:http://codeforces.com/problemset/problem/582/A


我们知道gcd(a, b)肯定小于等于a跟b

那么对于输入的那么多数字,设其中最大的数为m,那么m肯定是原序列的数之一,因为如果m不在原序列当中,由于其他数都比m小,就导致不可能有其他两个数a, b使得gcd(a, b) = m,m就用不掉了,所以我们就先把m加入原序列了,m与m的最大公约数就是它自己,所以在所有输入的数当中,m就这样被用掉了(有多个m的话就是用掉了一个,大家懂我意思就行)。然后在剩下的数当中,我们又可以找出其中最大的数来,理由同上,这个数又加入原序列,这时我们反推得到的原序列已经确定两位了,新加入的数要被用掉当然不用说,然后这新加入的数跟之前的m来个gcd,这gcd出来的数是拿来填表的,根据对称性还填了两个,也就是说,用了两个gcd的数,以后找没用过的数时就不考虑它们了。再后面我们把没用过的数当中最大的拿出来,跟已经在原序列中的所有数gcd,重复上述过程,最后我们就能得到原序列的所有数。

 

简洁点说,就是设输入的所有数为table[],已知原序列a为空,每次从table[]中找到最大的数x,从table[]中删掉,之后把x跟a里面所有数的gcd从table[]中各删去2个,再把x这个数push_back到a的后面,如此往复,直到table为空,我们就得到了合法的原序列a

 

怎么知道哪些数没用过呢?我们可以考虑用个桶装数,但是1e9有点大,所以就得进行离散化处理。

怎么找最大的数?排个序就行了


 

AC代码:

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

const int Maxn = 500 * 500 + 10;
vector<int> numbers; // 离散化
vector<int> origin; //输入的数据
int Count[Maxn]; //桶(离散化处理过的)
vector<int> a;

int gcd(int n, int m)
{
    return n % m == 0 ? m : gcd(m, n % m);
}

int get(int x)
{
    return lower_bound(numbers.begin(), numbers.end(), x) - numbers.begin();
}

int main()
{
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
    for (int i = 0; i < n * n; i++) {
        int x;
        cin >> x;
        origin.push_back(x);
        numbers.push_back(x);
    }

    sort(origin.begin(), origin.end()); //排序

    //离散化处理
    sort(numbers.begin(), numbers.end()); 
    numbers.erase(unique(numbers.begin(), numbers.end()), numbers.end());

    //装桶
    for (int i = 0; i < origin.size(); i++)
        Count[get(origin[i])]++;

    //问题解决部分
    for (int i = origin.size() - 1; i >= 0; i--) {
        if (Count[get(origin[i])] == 0) continue;

        int x = origin[i];
        a.push_back(x);
        Count[get(x)]--;

        for (int j = 0; j < a.size() - 1; j++)
            Count[get(gcd(a[j], x))] -= 2;
    }

    for (int i = 0; i < a.size(); i++)
        cout << a[i] << " ";

    return 0;
}

 

posted @ 2020-02-29 18:27  雾里尘埃  阅读(240)  评论(0编辑  收藏  举报