zoukankan      html  css  js  c++  java
  • 模拟赛1128

    https://www.luogu.org/contestnew/show/4300

    第一题。。

    第一眼数学题,第二眼lca,看了下数据范围,很明显连建边都建不了啊。。

    在想了想,对于每个月,新生的兔子是斐波那契数列的第f[i]+1-f[i+1]项,而分别对应1-。。

    想到这里正解就出来了,对于每个兔子,其父亲为x-最大的小于其的斐波那契数

    而要查询lca,则只需一只兔子暴力往上(查找父节点时二分),记录一路以来的节点

    对于另一只兔子,也只需往上跳,每到一个节点,二分查找一下前面那只兔子有没有到过

    时间复杂度(m*树的高度*log(树的高度)) 显然树的高度不会太高,所以平摊下来的时间还是理想的

    代码:

    const maxn=1000000000000;
    var
      i,j:longint;
      n,m,c,d,ll,l,ans:int64;
      f,tmp:array[1..100]of int64;
      flag:boolean;
    function find1(x:int64):longint;
    var
      h,t,mid:longint;
    begin
      h:=1; t:=l;
      while h<t do
      begin
        mid:=(h+t) div 2;
        if f[mid]>=x then t:=mid else h:=mid+1;
      end;
      if f[h]>=x then dec(h);
      exit(h);
    end;
    function find2(x:int64):boolean;
    var
      h,t,mid:longint;
    begin
      h:=1; t:=ll+1;
      while h<t do
      begin
        mid:=(h+t) div 2;
        if tmp[mid]=x then exit(true);
        if tmp[mid]<x then t:=mid else h:=mid+1;
      end;
      exit(false);
    end;
    begin
      f[1]:=1; f[2]:=1;
      for i:=3 to 100 do
      begin
        f[i]:=f[i-1]+f[i-2];
        if f[i]>maxn then break;
      end;
      l:=i;
      readln(n);
      for i:=1 to n do
      begin
        read(c,d); ll:=0; ans:=1; flag:=false;
        while c<>1 do
        begin
          inc(ll); tmp[ll]:=c;
          j:=find1(c);
          c:=c-f[j];
        end;
        while d<>1 do
        begin
          if find2(d) then
          begin
            ans:=d; break;
          end;
          j:=find1(d);
          d:=d-f[j];
        end;
        writeln(ans);
      end;
    end.

    第二题。。

    刚学完主席树不久。。。很明显的裸的主席树

    显然,主席树第一维维护区间,第二维维护各种颜色的个数

    注意到每次修改,实际上只有d1位置上各种颜色的兔子发生了变化,所以只需对d1处进行单点修改

    代码:

    uses math;
    type re=record
      h,t,x:longint;
    end;
    var
      p:array[0..20000000]of re;
      a,f:array[0..500000]of longint;
      n,m,i,j,tmp,c1,d1,e1,f1,ll:longint;
    procedure build(x,h,t:longint);
    var mid:longint;
    begin
      ll:=max(ll,x);
      p[x].h:=h; p[x].t:=t;
      if h=t then exit;
      mid:=(h+t) div 2;
      build(x*2,h,mid); build(x*2+1,mid+1,t);
    end;
    procedure insert(pre,x,h,t,sum:longint);
    var mid,tmp:longint;
    begin
      inc(ll); p[ll]:=p[pre]; inc(p[ll].x,sum); tmp:=ll;
      if h=t then exit;
      mid:=(h+t) div 2;
      if (x<=mid) then
      begin
        insert(p[ll].h,x,h,mid,sum);
        p[tmp].h:=tmp+1;
      end else
      begin
        insert(p[ll].t,x,mid+1,t,sum);
        p[tmp].t:=tmp+1;
      end;
    end;
    function query(x,y,z,h,t:longint):longint;
    var tmp,mid:longint;
    begin
      if h=t then exit(p[y].x-p[x].x);
      mid:=(h+t) div 2;
      if z<=mid then exit(query(p[x].h,p[y].h,z,h,mid))
      else exit(query(p[x].t,p[y].t,z,mid+1,t));
    end;
    begin
      readln(n,m);
      for i:=1 to n do read(a[i]);
      ll:=0;
      build(1,1,n);
      f[0]:=1;
      for i:=1 to n do
      begin
        f[i]:=ll+1;
        insert(f[i-1],a[i],1,n,1);
      end;
      for i:=1 to m do
      begin
        read(c1,d1);
        if c1=1 then
        begin
          read(e1,f1);
          writeln(query(f[d1-1],f[e1],f1,1,n));
        end
        else
        begin
          tmp:=ll;
          insert(f[d1],a[d1],1,n,-1);
          f[d1]:=tmp+1; tmp:=ll;
          insert(f[d1],a[d1+1],1,n,1);
          f[d1]:=tmp+1; tmp:=ll;
          tmp:=a[d1]; a[d1]:=a[d1+1]; a[d1+1]:=tmp;
        end;
      end;
    end.

    还是讲讲正解,vector+二分维护

    注意到这题的查询很简单,修改很特殊

    修改特殊在其没有改变相同颜色之间的相对顺序,所以可以考虑对于每个颜色开一个vector记录即可

    4.矩形确定两维后o(n)处理 常用思路

    5.

    6.序列问题我们要考虑一下差分 之后就简单了

  • 相关阅读:
    漫步温泉大道有感
    不可多得的”魔戒“:一堂成功学大师们的浓缩课
    四川新闻网关于IT诗人的报道
    赠徐蕴筝(帮别人名字作诗)
    再游草堂
    赠申芳菲(帮别人名字作诗)
    Oracle内部错误:ORA00600[15801], [1]一例
    Oracle内部错误:ORA00600[OSDEP_INTERNAL]一例
    Oracle O立方服务平台(O3SP)
    Oracle RAC内部错误:ORA00600[keltnfyldmInit]一例
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/7913389.html
Copyright © 2011-2022 走看看