CF582A 题解

有意思的思维题。

题意简述

由一个数列 {a1,a2,,an1,an}(1n500) 构造数表 b,其中 bi,j=gcd(ai,aj)。现在给出打乱之后的 b 的所有元素,要求还原 a

题目分析

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

证明:设 m=gcd(ai,aj)(不妨设 aiaj),则 maiaj=gcd(aj,aj)。而由于 gcd(aj,aj) 必为矩阵里的数,且 m 是表中最大的数,因此 mgcd(aj,aj)。所以 m=gcd(aj,aj)=aj,必在原序列中出现。

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

代码实现

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 @   Hadtsti  阅读(8)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示