模拟赛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.序列问题我们要考虑一下差分 之后就简单了

原文地址:https://www.cnblogs.com/yinwuxiao/p/7913389.html