1.题目难度(个人理解)
2.考察算法
暴力枚举
完全背包
树上二分
搜索DFS
基环树?
数学(找规律?)
树上DP
LCA倍增思想
动态DP?
3.题目分析
Day1T1.铺设道路(road)
考察算法:
暴力枚举,刷原题
解析:
其实这道题还是很有价值的,如果不是原题的话…
这题和NOIP2013Day2T1积木大赛一模一样,只是改了题面而已。
不过对于没做过原题的我,在考场上也是思考了一个多小时…
其实做法很简单,对于读入的第 块道路,只需比较它和第 块道路的深度,设 表示第 块道路的深度, 表示第 块道路的深度, 为答案:
若 ,则再填第 块道路时,第 块道路已经被填过了,所以不用进行任何操作。
若 ,则在填第 块道路时,第 块道路还有部分未被填完,此时需要将答案加上两块道路深度的差值,即
像这样从头到尾枚举一遍,问题就解决了,最后输出 ,时间复杂度接近
程序:
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原题大战?
这题算是很标准的树上二分题目,其实题目说道**“求最短路径的最大长度”**就已经可以明确是二分了,然而我在考场上打 函数打了将近两个小时,结果还炸了,看来以后也得加强编程能力啊!!!
Day2T1.旅行(travel)
考察算法:
暴力枚举,搜索DFS,基环树?
解析:
首先对于前 组数据:
这些数据的处理非常简单,只要从 号节点开始,在扩展时优先选择编号小的节点,对树进行一次DFS即可。时间复杂度接近 。
对于所有数据:
这些数据中,图是一棵基环树,简单的进行一次搜索无法得到正确答案。其实处理方法也很简单,我们先把通过搜索,把图中的环给找到,然后暴力断开环上的每一条边,并在每次断边后的图上进行一次DFS,最后取所有结果中的最优值即可。时间复杂度接近 。
程序:
期望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.
此题还有更优的 算法:具体解析和程序点这里
Day2T2.填数游戏(game)
考察算法:
数学推导,找规律?
解析:
说实话,我在考场上真没想到这题能找规律,我一直以为这是一个状压DP。后来经过大佬指点,才发现其实是能通过找规律AC的。但这题究竟标算是什么,我到现在也不了解,毕竟NOIP不会出一道打表找规律的题吧?而且这题不管是手摸,还是打表,想发现规律都异常困难,如果真考找规律,这题也是十分毒瘤了!
Day2T3.保卫王国(defense)
考察算法:
树上DP,LCA倍增思想,动态DP?
解析:
在考场上,我只想出了44分的暴力算法
考后听说是动态DP模板,可动态DP是NOI的考察内容啊!如果这题考动态DP,那超纲也太严重了吧。一定还有别的做法,在考后我经过反复思考,结合大佬的提示,终于发现了用LCA倍增思想解决问题的方法。