洛谷题单指南-进阶数论-CF582A GCD Table
原题链接:https://www.luogu.com.cn/problem/CF582A
题意解读:已知数列中每两个数的GCD(包括自己和自己的GCD),求原数列有哪些数。
解题思路:
由于GCD(a, b) <= min(a, b),
那么初始情况下GCD表中最大的数一定是数列中的数,
将最大的数从GCD表中移除,让后看剩下的数中最大的数,第二大的数也一定是数列中的数,
再把第二大的数移除,看第三大的数,第三大的数有可能是第一大的数和第二大的数的GCD,不能断定就是最大的数,
那么这样操作一下,将第一大和第二大的数的GCD也都移除,再看剩下的数里最大的数,必然是数列中的数。
因此,算法可以描述为:
1、将GCD表排序,用map记录每个数的个数
2、取最大的数,将此数移除(移除用map的个数减少来表示)
3、将此时最大的数和已经加入答案的数的GCD都移除
4、将此最大数加入答案
5、重复2操作
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 505;
int g[N * N];
unordered_map<int, int> mp;//记录某个数的出现次数
int ans[N], cnt;
int n;
int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a % b);
}
int main()
{
cin >> n;
for(int i = 1; i <= n * n; i++)
{
cin >> g[i];
mp[g[i]]++;
}
sort(g + 1, g + n * n + 1, greater<int>());
for(int i = 1; i <= n * n; i++)
{
int x = g[i];
if(mp[x] == 0) continue; //已经删除的,跳过
mp[x]--;
for(int i = 1; i <= cnt; i++)
{
int d = gcd(ans[i], x);
mp[d] -= 2;
}
ans[++cnt] = x;
if(cnt == n) break;
}
for(int i = 1; i <= n; i++) cout << ans[i] << " ";
return 0;
}
浙公网安备 33010602011771号