CERC 2013 Magical GCD

题目大意如下:给定一个序列,每个序列有值xi,现给定t个数列,对于每个长n的数列,求一段[l,r]使 [r-l+1]*gcd(l,r)最大,gcd(l,r)指的是该连续区间的最大公约数。

 

不难想到n^3,n^2logx,n^2的暴力吧

n^3DP,n^2logx暴力枚举,n^2DP

可以这样考虑,每次我对于某一个数,保存若干个值,以i为右端点的区间且gcd为某一值的时候这个区间最大的左端点位置是哪里?

但是你也许会认为这样做状态会不会有点多?更新是不是n方的呢?

其实不是的,因为我们可以从左到右来递推。

什么意思呢?对于每一个数,它与前面构成的gcd一定不会太多(约数肯定不会太多),所以我们最多也只需要保存每一个约数为gcd的时候左边最远能够拓展的位置。

其实远远不要保存每一个约数的位置,因为实际上很多的约数都不是gcd,这样我们就可以由左边的所有状态和右边的一个gcd一次来递推了。

当然,我们也可以直接利用指针的自动排序特性(类似链式前向星),我们碰到一个比当前(r-l+1)*val要小的就更新,因为我们再也尝试不到比它大的了。

{$inline on}



const maxn=100100;



type edge=^node;

    node=record

    next,last:edge;

    pos,val:int64;

end;



var head,tail:edge;

    e:array [0..maxn] of edge;

    n,cnt:longint;

    ans:int64;

    f:array [0..maxn] of int64;



procedure addedge(pos,value:int64); inline; 

var p:edge;

begin

    inc(cnt);

    new(p);

    p^.next:=head^.next;

    p^.last:=head;

    p^.next^.last:=p;

    p^.last^.next:=p;

    p^.pos:=pos; 

    p^.val:=value;

    e[cnt]:=p;

end;



procedure delete(var p:edge); inline;

begin

    p^.last^.next:=p^.next;

    p^.next^.last:=p^.last;

end;



procedure init; inline;

begin

    ans:=0;

    cnt:=0;

    head^.val:=0; tail^.val:=0;

    head^.next:=tail; tail^.last:=head;

    head^.last:=nil; tail^.next:=nil;

end;



function gcd(a,b:int64):int64; inline;

begin

    if a mod b=0 then exit(b)

    else exit(gcd(b,a mod b));

end;



function max(x,y:int64):int64; inline;

begin

   if x>y then exit(x)

   else exit(y);

end;



procedure main;

var t,value:int64;  i:longint; p:edge;

begin

    read(t);

    new(head); new(tail);

    while t<>0 do

        begin

            dec(t);

            init;

            read(n);

            ans:=0;

                for i:=1 to n do

                    begin

                        read(value);

                        addedge(i,value);

                        p:=head^.next;

                            while p<>tail do

                                begin

                                    p^.val:=gcd(p^.val,value);    

                                    ans:=max(ans,p^.val*(i-p^.pos+1));

                                    if p^.val=p^.last^.val then delete(p^.last);

                                    p:=p^.next;

                                end;

                    end;

            writeln(ans);

        end;

end;



begin

      main;

end.

 

你可能感兴趣的:(GC)