NOIP 2011 提高组 选择客栈(vijos 1737)(方法:队列,数学)
附: 题目链接 vijos 1737 地址:https://www.vijos.org/p/1737
srO 来自嘘嘘大神@oxxxo 的神级O(n) 打法 Orz
srO 而且该打法不长,可丧心病狂的压到10行 Orz
该题嘘嘘大神@oxxxo 的思路:
对于每个客栈(最低消费 v,格调 c),在、之前的、出现的所有、跟、该客栈、同格调的客栈、符合旅客要求、的前提是 :
在、这两客栈间存在一家最低消费<= p 的客栈,记 f 为离当前决策客栈、最近的、最低消费 <= p的、客栈编号,则、当前
决策点之前、能与该点、组成符合要求的、客栈即为:前 f 家客栈中、与该决策客栈同格调的客栈。
所以思路就很明显了:开一个 can[0..50] 的数组记录前 f 家客栈中格调为 x的数量,记为 can[x] ;则、当前决策点能增加
的方案数为 can[x] ,每次只要把 answer 的值加上 can[决策点]的值即可。
按这个思路,最后要完成的步骤就是: 对 can 这个数组的维护,按嘘嘘大神的方法,再开一个 tot[0..50] 数组、来记录:当
前决策点前、格调为 x的客栈数量,记为 tot[x] ; 以及用last[0..50] 来记录:上一个、格调为 x的客栈编号,记为 last[x]。
那么、每次决策时,只要先更新 f的值(即、如果该决策点、符合最低消费要求,则将、最近消费点f、更新为当前决策点);再判
断如果、 f 的值>= last[当前决策点格调] ,即上一个、和决策点 同格调的客栈编号,那么说明:离该点最近的、同格调的客栈、与
决策点之间、有符合最低消费的、客栈。那么就可以将 can[ x]的值更新为 tot[x] (x为当前决策点格调),因为出现的x格调都可记入
方案数。
然后看代码~~~~~
var
last,tot,can:array[0..51] of longint; //3个数组上面都有提到
n,k,p,i,answer,flag,color,cost:longint; //answer记录总方案数,flag为当前决策之前最近的消费点
begin
readln(n,k,p);
for i := 1 to n do begin
readln(color,cost); //采用边读边做,因为所有有用信息均有记录
if cost <= p then flag := i; //更新最近消费点
if flag >= last[color] then can[color]:=tot[color]; //更新 can 数组的值
inc(answer,can[color]); //记录前 i 点、与第 i 点、构成的、符合要求的方案数
inc(tot[color]); //更新tot 数组的值
last[color]:=i; //更新last 数组的值
end;
writeln(answer);
end.
Ps:因为对于每个客栈,f 更新一次,并将该客栈格调相关数组值更新,所以是相当科学的~~~~~~~~~~~~~~~~~
srO 附: 嘘嘘大神原题解链接 Orz
srO http://www.cnblogs.com/oxxxo/p/3370853.html Orz