NOIP2012提高组day2 T2借教室
这题骗分可以骗到满分(可能是数据不太强给强行过去了)
这道题如果是按照题意去模拟用循环去修改区间的话只有45分,正解是二分+差分数组,骗分也是差分数组但是没有使用二分,时间复杂度在最坏的情况下是O(n*m),数据良心并没有这种最坏的情况。
拿样例举例:
四天里,每一天的教室的可用数量为
2 5 4 3
读入订单,然后利用差分修改区间避免超时,不考虑教室的数量下限,修改后每一天的教室的可用数量为
0 -4 -5 -4
然后从第一天到最后一天遍历,如果当天的教室可用数量小于0,则当天的教室是不够用了的,模拟当天的情况,然后更新答案。
订单1:每天借两间,从第一天到第三天
订单2:每天借三间,从第二天到第四天
订单3:每天借四间,从第二天到第四天
第一天:0,不小于0
第二天:-4,小于0,模拟当天情况,原来的教室可用数量为5,从订单1到订单3模拟,第二天在订单1的区间内,教室的可用数量减去2,目前可用数量为3。 在订单2的区间内,可用数量减去3,目前可用数量变为0。 在订单3的区间内,可用数量减去4,目前可用数量为-4,在订单3时可用数量变为小于0,需要修改订单的订单为订单3,答案更新为3
第三天:-5,小于0,原来可用数量为4,在订单1的区间内,-2,可用数量变为2,在订单2的区间内,-3,可用数量变为-1,小于零,需要修改订单的订单为订单2,订单2的顺序在订单3之前,按照题意,先到先得,答案更新为2
第四天:………………(按照上面继续模拟)
骗分大法神奇qwq
贴上代码
1 var 2 n,m,i,j,k,ans:longint; 3 r,d,s,t,a,b:array[1..1000000] of longint; 4 flag:boolean; 5 begin 6 readln(n,m); 7 for i:=1 to n do 8 read(r[i]); //读入每天的可用教室数量 9 for i:=1 to m do 10 begin 11 readln(d[i],s[i],t[i]); //读入订单 12 a[s[i]]:=a[s[i]]-d[i]; 13 a[t[i]+1]:=a[t[i]+1]+d[i]; //差分数组预处理 14 end; 15 k:=0; 16 for i:=1 to n do 17 begin 18 k:=k+a[i]; 19 b[i]:=r[i]+k; //差分 20 end; 21 ans:=maxlongint; //ans初始化 22 flag:=true; //标记是否满足所有订单 23 for i:=1 to n do //枚举每天的可用教室 24 if b[i]<0 then //如果可用教室数量小于0 25 begin 26 flag:=false; //不可能满足所有订单 27 for j:=1 to m do 28 if (i<=t[j]) and (i>=s[j]) then //在订单j的区间内 29 if r[i]-d[j]<0 then //如果减去当前订单所需的教室数量小于0 30 begin 31 if j<ans then //如果小于ans,则更新ans 32 begin 33 ans:=j; 34 break; 35 end; 36 end 37 else 38 r[i]:=r[i]-d[j]; //减去当前订单所需的教室 39 end; 40 if flag then writeln('0') 41 else 42 begin 43 writeln('-1'); 44 writeln(ans); 45 end; 46 end.