CF582A 题解

有意思的思维题。

题意简述

由一个数列 $\{a_1,a_2,\cdots,a_{n-1},a_n\}(1\le n\le 500)$ 构造数表 $b$,其中 $b_{i,j}=\gcd(a_i,a_j)$。现在给出打乱之后的 $b$ 的所有元素,要求还原 $a$。

题目分析

这个题的突破口在于这样一个结论:表中最大的数 $m$,一定在原序列中出现。

证明:设 $m=\gcd(a_i,a_j)$(不妨设 $a_i\le a_j$),则 $m\le a_i\le a_j=\gcd(a_j,a_j)$。而由于 $\gcd(a_j,a_j)$ 必为矩阵里的数,且 $m$ 是表中最大的数,因此 $m\ge \gcd(a_j,a_j)$。所以 $m=\gcd(a_j,a_j)=a_j$,必在原序列中出现。

找到最大值之后就十分简单了。我们找到了最大值 $m$,也就求出了一项 $a_j$。我们只需要从表中剔除目前已知的与 $a_j$ 有关的所有 $\gcd(a_i,a_j)$ 后重复执行该过程即可。

代码实现

STL 浓度过高不喜勿喷

#include<bits/stdc++.h>
using namespace std;
int n,x;
map<int,int>S;
vector<int>ans;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n*n;i++)
        scanf("%d",&x),S[x]++;//把每个数直接扔进桶里
    while(!S.empty())//桶里还有就继续
    {
        auto i=S.end();
        i--;//找到最大的数对应的迭代器
        for(auto j:ans)//遍历 a 中已经确定的数
        {
            int tmp=__gcd(i->first,j);
            S[tmp]-=2;//删掉和当前最大数有关的所有 gcd(a_i,a_j),注意每个数在表里都出现 2 次,所以个数-=2。
            if(!S[tmp])//删没了就把迭代器也给删了
                S.erase(tmp);
        }
        ans.push_back(i->first);//把最大数扔到答案里
        i->second--;//删掉 gcd(a_j,a_j)
        if(!i->second)
            S.erase(i);//删没了就把迭代器也给删了
    }
    for(auto i:ans)
        printf("%d ",i);//输出
    return 0;
}
posted @ 2023-07-19 11:25  Hadtsti  阅读(4)  评论(0编辑  收藏  举报  来源