JZOJ.4699【NOIP2016提高A组模拟8.15】Password

来源:互联网 发布:阿里云迁移工具 编辑:程序博客网 时间:2024/05/10 23:19

Problem

Description

这里写图片描述

Input

这里写图片描述

Output

这里写图片描述

Sample Input

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

Sample Output

6 4 3 2

Data Constraint

这里写图片描述

Solution

我们发现,A序列原来是个矩阵,而B序列恰好是A序列矩阵的对角线。我们将A序列从大到小排个序,那么B1=A1(),B2=A2(),然后我们将Gcd(B1,B2)删掉,剩下的最大值是B3
每一次我们将Gcd(Ai,B1i1)删掉,然后Bi+1就是剩下数的最大值。
解决上述办法的方法有哈希和二分,这里主要讲二分。
我们设一个next数组,next[i]表示删掉i以后就要删next[i]。由于矩阵是对称的,所以一个数字一删就删掉2个。所以next[wz(两个数的最大公约数在数组里的最左边的位置)]+=2.

Code

#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<algorithm>#define N 1010#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;int i,j,l,r,mid,n,m,t,s,c,xb;int a[N*N],b[N],next[N*N];bool p,bz[N*N];bool cmp(int x,int y){return x>y;}int gcd(int x,int y) {if (y==0) return x; else return gcd(y,x%y);}int main(){    scanf("%d",&n);    fo(i,1,n*n) scanf("%d",&a[i]);    fo(i,1,n*n-1) next[i]=i;    sort(a+1,a+n*n+1,cmp);    b[1]=a[1];    b[0]=1;    if (n<=2)     {        fo(i,1,n) printf("%d ",b[i]);        return 0;    }    xb=1;    while (xb<=n*n)    {        xb++;        while (bz[xb]) xb++;        b[++b[0]]=a[xb];        if (b[0]==n) break;        fo(j,1,b[0]-1)        {            c=gcd(b[j],b[b[0]]);            l=xb+1;            r=n*n;            while (l<r)            {                mid=(l+r)/2;                if (a[mid]>c) l=mid+1;else r=mid;            }            int temp=next[l];            bz[temp]=bz[temp+1]=1;            next[l]+=2;        }    }    fo(i,1,n) printf("%d ",b[i]);}

——2016.8.15

3 0