1.题目难度(个人理解)

2.考察算法

暴力枚举

完全背包

树上二分

搜索DFS

基环树?

数学(找规律?)

树上DP

LCA倍增思想

动态DP?

3.题目分析

Day1T1.铺设道路(road)

考察算法:

暴力枚举,刷原题

解析:

其实这道题还是很有价值的,如果不是原题的话…

这题和NOIP2013Day2T1积木大赛一模一样,只是改了题面而已。

不过对于没做过原题的我,在考场上也是思考了一个多小时…

其实做法很简单,对于读入的第 ii 块道路,只需比较它和第 i1i-1 块道路的深度,设 a[i]a[i] 表示第 ii 块道路的深度, a[i1]a[i-1] 表示第 i1i-1 块道路的深度, ansans 为答案:

a[i1]a[i]a[i-1] \ge a[i] ,则再填第 i1i-1 块道路时,第 ii 块道路已经被填过了,所以不用进行任何操作。

a[i1]<a[i]a[i-1] < a[i] ,则在填第 i1i-1 块道路时,第 ii 块道路还有部分未被填完,此时需要将答案加上两块道路深度的差值,即 ans=ans+a[i]a[i1]ans=ans+a[i]-a[i-1]

像这样从头到尾枚举一遍,问题就解决了,最后输出 ansans ,时间复杂度接近 O(n)O(n)

程序:

program road;
var
   n,i,t,d:longint;
   sum:int64;

begin
  read(n);
  t:=0;
  for i:=1 to n do begin
    read(d);
    if d>t then inc(sum,d-t);
    t:=d;
  end;
  writeln(sum);
end.

Day1T2.货币系统(money)

考察算法:

装满型完全背包

解析:

这题据说也是原题,不过我是不知道原题是啥。

具体解析和程序点这里

Day1T3.赛道修建(track)

考察算法:

树上二分,树形DP

解析:

有大佬说这题还是原题!Day1原题大战?

这题算是很标准的树上二分题目,其实题目说道**“求最短路径的最大长度”**就已经可以明确是二分了,然而我在考场上打 checkcheck 函数打了将近两个小时,结果还炸了,看来以后也得加强编程能力啊!!!

具体解析和程序点这里

Day2T1.旅行(travel)

考察算法:

暴力枚举,搜索DFS,基环树?

解析:

首先对于前 1515 组数据:

这些数据的处理非常简单,只要从 11 号节点开始,在扩展时优先选择编号小的节点,对树进行一次DFS即可。时间复杂度接近 O(n)O(n)

对于所有数据:

这些数据中,图是一棵基环树,简单的进行一次搜索无法得到正确答案。其实处理方法也很简单,我们先把通过搜索,把图中的环给找到,然后暴力断开环上的每一条边,并在每次断边后的图上进行一次DFS,最后取所有结果中的最优值即可。时间复杂度接近 O(n2)O(n^{2})

程序:

期望60分:
program travel;
var
   l,v:array[0..10005]of longint;
   r,path:array[0..5005]of longint;
   tf:array[0..5005]of boolean;
   n,m,i,x,y,t,k:longint;

procedure sc(f,fa:longint);
var i,next:longint;
begin
  while true do begin
    next:=100000;
    i:=r[f];
    while i<>0 do begin
      if (tf[v[i]]=false) and (v[i]<next) and (v[i]<>fa) then next:=v[i];
      i:=l[i];
    end;
    if next=100000 then exit;
    tf[next]:=true;
    inc(k);
    path[k]:=next;
    sc(next,f);
  end;
end;

begin
  read(n,m);
  fillchar(r,sizeof(r),0);
  fillchar(tf,sizeof(tf),0);
  fillchar(l,sizeof(l),0);
  fillchar(v,sizeof(v),0);
  fillchar(path,sizeof(path),0);
  for i:=1 to m do begin
    read(x,y);
    t:=2*i;
    l[t]:=r[x];
    r[x]:=t;
    v[t]:=y;
    l[t-1]:=r[y];
    r[y]:=t-1;
    v[t-1]:=x;
  end;
  k:=1;
  path[k]:=1;
  tf[0]:=true;
  sc(1,0);
  for i:=1 to k do write(path[i],' ');
end.
期望100分:
program project1;
var
   r,path,father,son,ans:array[0..5005]of longint;
   tf:array[0..5005]of boolean;
   l,v:array[0..10005]of longint;
   n,m,i,x,y,t,k,p,fat:longint;

procedure sc(f,fa:longint);
var i,next:longint;
begin
  while true do begin
    next:=100000;
    i:=r[f];
    while i<>0 do begin
      if (v[i]<next) and (v[i]<>fa) and (tf[v[i]]=false) and (v[i]<>0) then next:=v[i];
      i:=l[i];
    end;
    if next=100000 then exit;
    tf[next]:=true;
    inc(k);
    path[k]:=next;
    sc(next,f);
  end;
end;

function min:boolean;
var i:longint;
begin
  for i:=1 to n do
    if ans[i]>path[i] then exit(true)
      else if ans[i]<path[i] then exit(false);
  exit(false);
end;

function del(f,fa:longint):boolean;
var i:longint;
begin
  del:=false;
  i:=r[f];
  while i<>0 do begin
    if v[i]<>fa then begin
      if father[v[i]]=0 then father[v[i]]:=f
        else begin
          p:=v[i];
          fat:=father[v[i]];
          father[v[i]]:=f;
          son[f]:=v[i];
          exit(true);
        end;
      if del(v[i],f)=true then begin
        son[f]:=v[i];
        exit(true)
      end;
    end;
    i:=l[i];
  end;
end;

procedure cut(x,y:longint);
var i,j:longint;
begin
  i:=r[x];
  while i<>0 do begin
    if v[i]=y then begin
      v[i]:=0;
      if i mod 2=0 then j:=i-1 else j:=i+1;
      v[j]:=0;
      fillchar(tf,sizeof(tf),0);
      fillchar(path,sizeof(path),0);
      k:=1;
      path[k]:=1;
      sc(1,0);
      if min=true then ans:=path;
      v[i]:=y;
      v[j]:=x;
      exit;
    end;
    i:=l[i];
  end;
end;

procedure point(p:longint);
var i:longint;
begin
  i:=p;
  cut(i,son[i]);
  i:=son[i];
  while i<>p do begin
    cut(i,son[i]);
    i:=son[i];
  end;
end;

begin
  read(n,m);
  fillchar(tf,sizeof(tf),0);
  fillchar(path,sizeof(path),0);
  fillchar(ans,sizeof(ans),$5f);
  k:=0;
  for i:=1 to m do begin
    read(x,y);
    t:=i*2;
    l[t]:=r[x];
    r[x]:=t;
    v[t]:=y;
    l[t-1]:=r[y];
    r[y]:=t-1;
    v[t-1]:=x;
  end;
  inc(k);
  path[k]:=1;
  father[1]:=1;
  if m=n then begin
    del(1,0);
    point(p);
  end
  else begin sc(1,0);ans:=path; end;
  for i:=1 to n do write(ans[i],' ');
end.

此题还有更优的 O(nlogn)O(n \log n) 算法:具体解析和程序点这里

Day2T2.填数游戏(game)

考察算法:

数学推导,找规律?

解析:

说实话,我在考场上真没想到这题能找规律,我一直以为这是一个状压DP。后来经过大佬指点,才发现其实是能通过找规律AC的。但这题究竟标算是什么,我到现在也不了解,毕竟NOIP不会出一道打表找规律的题吧?而且这题不管是手摸,还是打表,想发现规律都异常困难,如果真考找规律,这题也是十分毒瘤了!

具体解析和程序点这里

Day2T3.保卫王国(defense)

考察算法:

树上DP,LCA倍增思想,动态DP?

解析:

在考场上,我只想出了44分的暴力算法

考后听说是动态DP模板,可动态DP是NOI的考察内容啊!如果这题考动态DP,那超纲也太严重了吧。一定还有别的做法,在考后我经过反复思考,结合大佬的提示,终于发现了用LCA倍增思想解决问题的方法。

具体解析和程序点这里