JZOJ链接 (原题CF583C) 粗略的大意就是给出一个n*n的被打乱的序列A,其中每个A序列中的数都是B序列中两个数的Gcd 即对于任意 Ai ,有 Ai=Gcd(Bj,Bk)(1≤j,k≤N) ,且j,k不重复 求原来的B数组,B是不下降的(可以把它当成输出格式)。 首先我们就要尝试研究Gcd的性质 首先容易想到, Gcd(a,a)=a 因此A序列中有N项是B序列的 而且 Gcd(a,b)≤a,b 因此在A序列之中,B[1]一定是那个最大的数。 于是我们把A序列从大到小排序后,最大的数(A[1])就是B[1] 不难想到A[2]是B[2],但A[3]一定是B[3]吗? 不一定,还有可能是Gcd(B[1],B[2])。 所以我们可以想到这样的思路:每当我们把当前A序列中最大的数取出来到B数组时,假设当前是第i个,则在A序列中删掉这个数和前面i-1个数的Gcd,而且因为A数组中有着 Gcd(Bi,Bj) ,也有 Gcd(Bj,Bi) ,所以这个数要删掉两次。 因为 1≤Ai≤109 ,所以我们需要用Hash表(或许离散化也可以)存取记录每个数剩余的数量,排序后扫一遍即可。 算法的最坏复杂度为 O(n2) ,因为 1≤n≤103 ,复杂度可以接受。
代码
var a,h,ct:array[0..10000000] of longint; f:array[0..1000] of longint; n,m,i,j,k,x:longint; procedure qsort(l,r:longint); var i,j,mid,t:longint; begin i:=l; j:=r; mid:=a[(i+j) shr 1]; repeat while a[i]>mid do inc(i); while a[j]<mid do dec(j); if i<=j then begin t:=a[i]; a[i]:=a[j]; a[j]:=t; inc(i); dec(j); end; until i>j; if j>l then qsort(l,j); if i<r then qsort(i,r); end; function hash(x:longint):longint; var i:longint; begin i:=x mod 9100009; while (h[i]<>0)and(h[i]<>x) do i:=(i mod 10000000)+1; h[i]:=x; exit(i); end; function gcd(x,y:longint):longint; begin if x mod y=0 then exit(y) else exit(gcd(y,x mod y)); end; begin assign(input,'data.in');reset(input); assign(output,'data.out');rewrite(output); readln(n); m:=n*n; for i := 1 to m do read(a[i]); qsort(1,m); for i := 1 to m do begin x:=hash(a[i]); inc(ct[x]); end; k:=0; for i := 1 to m do begin x:=hash(a[i]); if ct[x]>0 then begin inc(k); f[k]:=a[i]; dec(ct[x]); for j := 1 to k-1 do begin x:=gcd(f[k],f[j]); dec(ct[hash(x)],2); end; end; if k=n then break; end; for i := 1 to n do write(f[i],' '); close(input);close(output); end.