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

Password

题目大意

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
请你求出密码序列 B

数据范围

这里写图片描述

题解

这一题比较好玩,如果想得出来,就很简单,否则就很难。
首先将A序列从大到小排序, Ans1 = A1 Ans2 = A2 ,这很显然。
现在我们考虑 Ans3 Ans3 是否就是第三大呢?
我们知道,可能比 Ans3 大的也就只有gcd( Ans1 Ans2 )了。
那我们在找 Ans3 之前把2个gcd( Ans1 Ans2 )从 A 序列中去掉就行了。
同理,我们找到Ansi后,把两个gcd( Ans1 ~ Ansi1 , Ansi )从序列去掉后,下一个找到的没被去掉 Aj 的就是 Ansi+1

去掉操作可以用哈希来维护。

Code(Pascal)

const
    mo=1000007;
var
    n,m,j,k,l,i,o,p:longint;
    ans:array[0..2000] of longint;
    ha:array[0..1000007,1..2] of int64;
    a:array[0..2000000] of int64;
procedure qsort(l,r:longint);
    var
        i,j:longint;
        m:int64;
    begin
        i:=l;
        j:=r;
        m:=a[(l+r) div 2];
        repeat
            while a[i]>m do inc(i);
            while a[j]<m do dec(j);
            if i<=j then
            begin
                a[0]:=a[i];
                a[i]:=a[j];
                a[j]:=a[0];
                inc(i);
                dec(j);
            end;
        until i>j;
        if l<j then qsort(l,j);
        if i<r then qsort(i,r);
    end;
function gcd(a,b:int64):int64;
    var
        t:int64;
    begin
        t:=0;
        repeat
            t:=a mod b;
            a:=b;
            b:=t;
        until t=0;
        exit(a);
    end;
procedure zj(o:longint);
    var
        m:longint;
    begin
        m:=o mod mo;
        while (ha[m,1]<>0) and (ha[m,1]<>o) do
        m:=(m+1) mod mo;
        ha[m,1]:=o;
        inc(ha[m,2],2);
    end;
function ok(o:longint):boolean;
    var
        m:longint;
    begin
        m:=o mod mo;
        while (ha[m,1]<>0) and (ha[m,1]<>o) do
        m:=(m+1) mod mo;
        ha[m,1]:=o;
        if ha[m,2]=0 then exit(true);
        dec(ha[m,2]);
        exit(false);
    end;
begin
    readln(n);
    for i:=1 to n*n do
    read(a[i]);
    qsort(1,n*n);
    ans[1]:=a[1];
    ans[2]:=a[2];
    zj(gcd(ans[1],ans[2]));
    k:=2;
    for i:=3 to n*n do
    if ok(a[i]) then
    begin
        inc(k);
        ans[k]:=a[i];
        for l:=1 to k-1 do
        zj(gcd(ans[l],ans[k]));
    end;
    for i:=1 to n do
    write(ans[i],' ');
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值