外卖店优先级
题目分析
这一题一看N,M,T的范围就知道不能暴力,要讨巧,怎么讨巧是重点。正常的思路是第一层for循环遍历订单(或者外卖店),第二层for循环遍历外卖店(或者订单),这样可以求出每个外卖店是不是在缓存里面,但是时间复杂度是 O ( N ∗ M ) = 1 e 10 > 1 e 8 O(N*M)=1e10>1e8 O(N∗M)=1e10>1e8,明显是不行的。
说一下讨巧的思路,订单我是必然要遍历的不然你不知道哪个外卖店有单子,那么可以不遍历外卖店吗?这就看我们如何处理订单了。订单应该是一个类,包含时间ts和外卖店id,我们优先对订单按照外卖店id排序,id相同时再按照ts排序,排序规则如下,
static class message implements Comparable<message>{//存储订单信息int id,t;//订单的id和时间public message(int t, int id) {this.id = id;this.t = t;}@Overridepublic int compareTo(message o) {if(this.id != o.id) {return this.id-o.id;}else {return this.t-o.t;} } }
现在可以开始遍历订单了,在遍历的时候我要记录两个值,一个是cnt用来表示当前外卖店的优先级大小,一个是flag用来表示当前外卖店是否被放在缓存里面。一个是ans表示我知道的在缓存里面的外卖店的数量。
int flag = 0;//表示是否在优先级缓存中,在的flag=1,
int ans = 0;//记录答案
int cnt = 2;//表示外卖店的优先级大小
对于当前订单me[i],我要知道前一个订单me[i-1]是否和他是同一个外卖店,如果是,那么说明我此时把me[i-1].id的外卖店的单子都遍历完了,此时我要确定他是不是在缓存里面。两步确定法,一是确定flag是否等于1,二十确定从最后一个单子的时间到时间t内,是否会使他的优先级减少到小于等于3的情况。
if(me[i].id!=me[i-1].id) {//如果变成下一个外卖店了,就要检查刚刚那个外卖店是不是在缓存中的//falg=1并且到达t时,没有小于等于3if(flag == 1 && (cnt - (t - me[i-1].t) > 3 )) {ans++;}cnt = 2;//此时是me[i].id有单子,那么cnt初始值应该是2flag = 0;//重置flag
}
否则的话,先求从上一个订单到当前这个订单,外卖店的优先级降低了多少,也就是经历的时间。那么这里为什么是int diff = me[i].t - me[i-1].t - 1;
呢?举个例子,假设当前的时间是4,前一个的时间是2,那么中间没有订单的时间就是ts=3时,因此优先级应该降低1,那么也就是4-2-1。但是注意,如果出现了当前的时间是4,前一个的时间也是4,会出现4-4-1=-1的情况,但是实际此时应该优先级降低0,所以会有if(diff == -1) diff = 0;
。那么这个if(cnt <= 3)
一定要在cnt += 2;
之前判断,举个例子,假设外卖店的当前优先级是4,那么diff=2,4减2等于2,此时应该被移出优先级缓存的,但是如果在判断之前我先给他加了2,那么此时2+2=4>3,他就不会移出优先级缓存,造成结果错误。
else {int diff = me[i].t - me[i-1].t - 1;//优先级降低了多少 me[i].t=1 me[i-1].t=1if(diff == -1) diff = 0;cnt = Math.max(0, cnt - diff);//如果优先级降低到了负数,那么他就是0if(cnt <= 3) flag = 0;//如果小于等于3会被移出缓存cnt += 2;//出现了订单,优先级加2.if(cnt > 5) flag = 1;//如果大于5会被加入缓存
}
注意,最后一个外卖店,我没有判断它是否在缓存里面,所以for循环结束后要判断
//对最后一个订单/最后一个外卖店进行判断
if(flag == 1 && (cnt - (t - me[m-1].t) > 3 )) {ans++;
}
System.out.println(ans);
题目代码
import java.util.Arrays;
import java.util.Scanner;
public class Main{static class message implements Comparable<message>{//存储订单信息int id,t;//订单的id和时间public message(int t, int id) {this.id = id;this.t = t;}@Overridepublic int compareTo(message o) {if(this.id != o.id) {return this.id-o.id;}else {return this.t-o.t;} } }
public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int m = scanner.nextInt();int t = scanner.nextInt();message[] me = new message[m];for (int i = 0; i < me.length; i++) {me[i] =new message(scanner.nextInt(), scanner.nextInt());}Arrays.sort(me);int flag = 0;//表示是否在优先级缓存中,在的flag=1,int ans = 0;//记录答案int cnt = 2;//表示外卖店的优先级大小for (int i = 1; i < m; i++) {if(me[i].id!=me[i-1].id) {//如果变成下一个外卖店了,就要检查刚刚那个外卖店是不是在缓存中的//falg=1并且到达t时,没有小于等于3if(flag == 1 && (cnt - (t - me[i-1].t) > 3 )) {ans++;}cnt = 2;//此时是me[i].id有单子,那么cnt初始值应该是2flag = 0;//重置flag}else {int diff = me[i].t - me[i-1].t - 1;//优先级降低了多少 me[i].t=1 me[i-1].t=1if(diff == -1) diff = 0;cnt = Math.max(0, cnt - diff);if(cnt <= 3) flag = 0;cnt += 2;if(cnt > 5) flag = 1;}}//对最后一个订单/最后一个外卖店进行判断//讲日期模拟器的时候,whie循环结束后,也得有一个if语句,对最后一个日期进行检查if(flag == 1 && (cnt - (t - me[m-1].t) > 3 )) {ans++;}System.out.println(ans);
}
}