• bzoj2790


    观察这道题,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
  • 相关阅读:
    面向对象基础
    JS操作属性和样式
    表单验证
    form标签
    Dreamweaver网页设计代码大全
    最差项目展示
    CSS样式表
    while循环 do while循环 switch
    for循环
    穷举法
  • 原文地址:https://www.cnblogs.com/phile/p/4533513.html
Copyright © 2020-2023  润新知