1241. 外卖店优先级 Java题解 (模拟)【第十届蓝桥杯省赛C++A/C组,JAVA A/B/C组】

35 篇文章 2 订阅
11 篇文章 0 订阅

输入样例:

2 6 6
1 1
5 2
3 1
6 2
2 1
6 2

 输出样例:

1

样例解释

66 时刻时,11 号店优先级降到 33,被移除出优先缓存;22 号店优先级升到 66,加入优先缓存。

所以是有 11 家店 (22 号) 在优先缓存中。


解题思路:

最直接的暴力想法是:通过枚举每个店的 0~ t的时间来判断到t时刻时,优先级是否在缓存中。但由于店数和时间都是10^5,平方的复杂度肯定会超时,并且因为要同时记录店铺,时间,订单数,需要用到二维数组,也会内存超限。

优化:可以注意到订单的数量也是10^5,与店数规模相同,可以看出平均每个店只有一个订单,是非常离散化的,所以当遍历订单时,时间复杂度可以降为O(n)。

可以先按订单的时间排序,依次遍历,遍历每份订单时,由于时间并不连续,所以为了可以知道上一份订单的时间(用来降低优先级),需要开一个数组,用来表示每个店最后一次出现订单的时刻,可以直接算出"一长段"时间的优先级,遍历完时,还需要将与t之前的没有出现订单的优先级降低。同时再开一个数组再记录每个店是否在优先缓存中,最后统计数量。

Java代码:O(nlogn) 

import java.io.*;
import java.util.*;

public class Main {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String[] split = br.readLine().split(" ");
		int n = Integer.parseInt(split[0]);//外卖店数量
		int m = Integer.parseInt(split[1]);//订单总数
		int t = Integer.parseInt(split[2]);//时间
		int []pri = new int[n + 1];//priority:优先先数组 pri[i] = j: 表示第i个店的优先级为j
		int []last = new int[n + 1];//last[i]=j :表示第i个店最近一次有订单的时间是第j秒
		boolean []flag = new boolean[t + 1];//表示该店是否已经进入优先缓存中
		
		List<Inf1241> list = new ArrayList<>();//存储订单
		for(int i = 0; i < m; i++) {
			split = br.readLine().split(" ");
			int ts = Integer.parseInt(split[0]);
			int id = Integer.parseInt(split[1]);
			list.add(new Inf1241(ts, id));
		}
		Collections.sort(list);//将所有订单按订单的时间排序
		
		for(int i = 0; i < m; ) {//遍历订单,因为可能有重复订单,i的下标由重复订单的数量决定
			int j = i;
			while(j < m && list.get(j).ts == list.get(i).ts && list.get(j).id == list.get(i).id) j++;//循环结束时,j指向新的一份订单
			int ts = list.get(j - 1).ts, id = list.get(j - 1).id, cnt = j - i;//cnt:有重复订单的数量
			i = j;//方便下一次循环
			
			pri[id] -= ts - last[id] - 1;//因为订单的时间不是连续的,通过last数组处理之前的优先级(注意边界)
			if(pri[id] < 0) pri[id] = 0;//优先级最低为0
			if(pri[id] <= 3) flag[id] = false;
			
			pri[id] += cnt * 2;//处理此时的新的订单
			if(pri[id] > 5) flag[id] = true;
			last[id] = ts;//记录该店最后一次有订单的时间
		}
		
		for(int i = 1; i <= n; i++) //最后一段时间可能存在有店持续没有订单,需要降低优先级
			if(last[i] < t) {
				 pri[i] -= t - last[i];//(注意边界)
				 if(pri[i] <= 3) flag[i] = false;
			}
		
		int ans = 0;
		for(boolean data : flag) if(data) ans++;
		System.out.println(ans);
	}
}
class Inf1241 implements Comparable<Inf1241>{
	int ts;
	int id;
	
	public Inf1241(int ts, int id) {
		this.ts = ts;
		this.id = id;
	}
	
	@Override
	public int compareTo(Inf1241 o) {
		if(this.ts != o.ts) return this.ts -o.ts;
		else return this.id - o.id;
	}
}

Java代码:O(n^2)

import java.io.*;

public class Main {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String[] split = br.readLine().split(" ");
		int n = Integer.parseInt(split[0]);//店铺数
		int m = Integer.parseInt(split[1]);//订单总数
		int t = Integer.parseInt(split[2]);//时间
		int [][]pri = new int[n + 1][t + 1];//优先缓存
		
		for(int i = 0; i < m; i++) {
			split = br.readLine().split(" ");
			int ts = Integer.parseInt(split[0]);
			int id = Integer.parseInt(split[1]);
			pri[id][ts]++;//表示第id个店第ts秒的订单数量
		}
		
		int ans = 0;
		for(int i = 1; i <= n; i++) {//枚举外卖店
			int s = 0;//第i个店的优先级
			for(int j = 1; j <= t; j++) {//枚举时间
				if(pri[i][j] != 0) {//有订单时
					s += pri[i][j] * 2;
				}else {//没有订单
					if(s > 0)s--;
				}
			}
			if(s > 5)ans++;
			else if(s == 4 && pri[i][t] == 0 && t >=1 && pri[i][t - 1] == 0)ans++;//优先级4可能是被降下来的,仍然在缓存中
			else if(s == 5 && pri[i][t] == 0)ans++;
		}
		System.out.println(ans);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值