观察这道题,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.