Password【NOIP2016提高A组模拟8.15】

来源:互联网 发布:歌曲字幕制作软件 编辑:程序博客网 时间:2024/04/28 12:13

题目

这里写图片描述
样例输入:
这里写图片描述
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]);} 

这里写图片描述

0 0
原创粉丝点击