JZOJ 4699 Password

题目大意

有一个单调不升的序列B,由B的数两两求gcd得出A。现在给出A,求B。
n<=1000,a[i]<=1e9
时间限制 1.5s
空间限制 256M

解题思路

首先A中最大的两个数一定是B中最大的两个数,而唯一比B[3]大的数只有可能是gcd(B[1],B[2]),所以在A中去掉gcd(B[1],B[2])(注意是2个)后,最大的数就是B[3]。
由此类推,B序列中每确定一个数,就把它与前面的数的gcd从A序列中去掉,然后后一个数就是A序列中剩余的最大的数了。

#include<cstdio>
#include<algorithm>
#define maxn 1006
#define fr(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const ll ding=10000007;
bool cmp(int a,int b)
{
    return a>b;
}
int i,j,n,t,tot,h[ding+10][2],a[maxn*maxn],b[maxn*maxn];
int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}
int hash(int x)
{
    int t=(x-1)%ding+1;
    while (h[t][0]!=0 && h[t][0]!=x)
        t=t%ding+1;
    h[t][0]=x;
    return t;
}
int main()
{
    scanf("%d",&n);
    fr(i,1,n*n) 
    {
        scanf("%d",&a[i]);
        t=hash(a[i]);
        h[t][1]++;
    }
    sort(a+1,a+n*n+1,cmp);
    b[1]=a[1],b[2]=a[2],tot=2;
    t=hash(a[1]),h[t][1]--;
    t=hash(a[2]),h[t][1]--;
    t=hash(gcd(a[1],a[2])),h[t][1]-=2;
    fr(i,3,n*n)
    {
        t=hash(a[i]);
        if (h[t][1]>0) h[t][1]--,b[++tot]=a[i];
        if (tot==n) break;
        fr(j,1,i-1)
        {
            t=hash(gcd(a[i],a[j]));
            h[t][1]-=2;
        }
    }
    fr(i,1,n) printf("%d ",b[i]);
    printf("\n");
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章