观察这道题,d(a,b) 就是先变成最大公约数然后再变成b

设g[x]表示x的质因数数目,不难得到d(a,b)=g[a/gcd(a,b)]+g[b/gcd(a,b)]

因为g[xy]=g[x]+g[y] 所以d(a,b)=g[a/gcd(a,b)]+g[b/gcd(a,b)]=g[a]+g[b]-2*g[gcd(a,b)]

g[]很明显可以用线性筛搞出来,下面考虑如何解决询问

我们发现从穷举是序列中哪个数来考虑,是无法优化的

考虑穷举约数(穷举约数是根号的复杂度,这是一个非常经典的转化)

设f[x]表示在序列中是x倍数的元素g[]最小且编号尽量小的

因为对于每个i,j不等于i,所以我们还要维护一个次优值

这一步我们可以O(n√a)的复杂度

然后我们对于每个元素,我们只要穷举约数,在这个约数是最大公约数的情况下的最优值即可

有人说,如果记录的f[x]的元素和当前询问元素的最大公约数是x的倍数而不是x怎么办

丝毫不影响,因为d(a,b)=g[a]+g[b]-2*g[gcd(a,b)],g[ax]>=g[x] a是正整数

如果这个更新了,那到后面那个最大公约数时肯定会被再更新

 1 const inf=1000000007;
 2 var f,w:array[0..1000010,1..2] of longint;
 3     p,a,g:array[0..1000010] of longint;
 4     k,mx,i,t,n,j,ans:longint;
 5 
 6 function min(a,b:longint):longint;
 7   begin
 8     if a>b then exit(b) else exit(a);
 9   end;
10 
11 function cmp(a1,b1,a2,b2:longint):boolean;
12   begin
13     if a1=a2 then exit(b1<b2);
14     exit(a1<a2);
15   end;
16 
17 procedure work(x,i:longint);
18   begin
19     if cmp(g[a[i]],i,f[x,0],w[x,0]) then
20     begin
21       f[x,1]:=f[x,0];
22       w[x,1]:=w[x,0];
23       f[x,0]:=g[a[i]];
24       w[x,0]:=i;
25     end
26     else if cmp(g[a[i]],i,f[x,1],w[x,1]) then
27     begin
28       f[x,1]:=g[a[i]];
29       w[x,1]:=i;
30     end;
31   end;
32 
33 procedure get(x,i:longint);
34   begin
35     if w[x,0]=i then
36     begin
37       if w[x,1]=0 then exit;
38       if cmp(f[x,1]-2*g[x],w[x,1],ans,k) then
39       begin
40         ans:=f[x,1]-2*g[x];
41         k:=w[x,1];
42       end;
43     end
44     else if cmp(f[x,0]-2*g[x],w[x,0],ans,k) then
45     begin
46       ans:=f[x,0]-2*g[x];
47       k:=w[x,0];
48     end;
49   end;
50 
51 begin
52   readln(n);
53   for i:=1 to n do
54   begin
55     read(a[i]);
56     if mx<a[i] then mx:=a[i];
57   end;
58   g[1]:=0;
59   for i:=2 to mx do
60   begin
61     if g[i]=0 then
62     begin
63       g[i]:=1;
64       inc(t);
65       p[t]:=i;
66     end;
67     for j:=1 to t do
68     begin
69       if i*p[j]>mx then break;
70       g[i*p[j]]:=g[i]+1;
71       if i mod p[j]=0 then break;
72     end;
73   end;
74   for i:=1 to mx do
75   begin
76     f[i,0]:=inf;
77     f[i,1]:=inf;
78   end;
79   for i:=1 to n do
80     for j:=1 to trunc(sqrt(a[i])) do
81       if a[i] mod j=0 then
82       begin
83         work(j,i);
84         if j*j<>a[i] then work(a[i] div j,i);
85       end;
86 
87   for i:=1 to n do
88   begin
89     ans:=inf;
90     k:=0;
91     for j:=1 to trunc(sqrt(a[i])) do
92       if a[i] mod j=0 then
93       begin
94         get(j,i);
95         if j*j<>a[i] then get(a[i] div j,i);
96       end;
97     writeln(k);
98   end;
99 end.
View Code

 

posted on 2015-05-27 15:13  acphile  阅读(202)  评论(0编辑  收藏  举报