您的位置:首页 > 其它

Password【NOIP2016提高A组模拟8.15】

2016-08-15 20:37 316 查看

题目



样例输入:



4

1 1 2 2 3 4 6 2 2 1 3 2 2 1 3 2

样例输出:



6 4 3 2

数据范围:



剖解题目

有一个N位B数组,经过一个公式得到了N*N的A数组,现将A数组打乱,让你找回B数组。

思路

应该仔细研究两个数组之间的关系,没有其他想法了吧…….

解法

20%:因为所有的数都是互质的,只需要把gcd不是1的数拿出来,然后排个序输出。

?%:会发现,这N个数中,每两个数都会是A数组中两个位置的答案,每个数对应着一个位置,只需要将A数组中,出现次数为奇数的拿出来,排序输出。

?%:有人水了90分,表示这分来历不明不懂。

100%:其实这N*N个数就是对应着一个矩阵,这个矩阵沿着对角线对称,对角线上的数就是答案。

显然,最大的数一定是答案的第一个,第二大的数也是答案第二个,第三个还是吗?我们发现比第三个大的数除去第一第二以外,只有可能是第一个与第二个数的gcd,那么如果这个gcd不等于第三个的话,那第三个就是答案之一。

所以,我们每次从A数组(已经排好序),取出一个数A[i],我们把我们的ans数组中每个与A[i]的gcd在A数组中都删掉,而且要删两次(因为每两个数是对应这A数组中的两个位置),再选择A数组中剩下的最大值即可。

然而,a[i]<=109,桶肯定不行,我们需要用到hash等一些列可离散化的东西,作为一名C++选手,就偷懒的用了map了。

代码

#include<map>
#include<cstdio>
#include<algorithm>
#include<functional>
#include<cstdlib>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)

using namespace std;

const int maxn=1005,maxnn=1000005;
int n,ans[maxn],a[maxnn];
map<int,int> cy;

int gcd(int x,int y)
{
if (!y) return x;
else return gcd(y,x%y);
}
int main()
{
freopen("T.in","r",stdin);
scanf("%d",&n);
fo(i,1,n*n) {
scanf("%d",&a[i]);
cy[a[i]]++;
}
sort(a+1,a+n*n+1,greater<int>());
ans[++ans[0]]=a[1];
fo(i,2,n*n)
if (cy[a[i]]>0){
fo(j,1,ans[0]){
int x=gcd(a[i],ans[j]);
cy[x]-=2;
}
if (cy[a[i]]>0) {
ans[++ans[0]]=a[i];
cy[a[i]]--;
}
if (ans[0]==n) break;
}
fo(i,1,ans[0]) printf("%d ",ans[i]);
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  gcd