1 借教室
题解
由于订单数量的增加,会导致某一天的教室订单数量要高于实际可预约的教室数量,所以可以使用二分查找的思想查找哪一天的实际数量要小于需要预约的数量。由于租客连续的进行租借,可以使用差分来进行区间之间的加减操作;
import java.io.*;
import java.util.*;
public class Main{
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
static final int N = (int) 1e6 + 10 ; //题目需要的最大数量范围
static int[] d =new int[N],s = new int[N], t = new int[N] ;
static int[] w = new int[N];
static long[] b = new long[N] ;
static int n,m;
public static void main(String[] args) throws IOException{
String[] s1 = br.readLine().split(" ");
n = Integer.parseInt(s1[0]) ;
m = Integer.parseInt(s1[1]) ;
String[] s2 = br.readLine().split(" ");
for(int i = 1; i <= n; i ++){
w[i] = Integer.parseInt(s2[i-1]) ;
}
for(int i = 1; i <= m; i ++){
String[] s3 = br.readLine().split(" ");
d[i] = Integer.parseInt(s3[0]) ;
s[i] = Integer.parseInt(s3[1]);
t[i] = Integer.parseInt(s3[2]) ;
}
//标准二分查找
int l = 0,r = m;
while(l < r){
int mid = l + r + 1>> 1;
if(check(mid)) l = mid ;
else r = mid - 1 ;
}
if(r == m){
System.out.println(0);
}else{
System.out.println(-1);
System.out.println(r + 1);
/*
* 当我们跳出while循环的时候 r = mid - 1;
* 所以当不成立的时候 就需要r+1;
* 那为什么r == m时候 不需要 +1 判断呢
* r= m 是极大的情况 即 所有条件都满足 那么此时是 l = mid && l == r,所以不需要加1 ;
*/
}
}
static boolean check(int mid){
Arrays.fill(b,0) ;
//利用差分获得每一天的预约数量
for(int i = 1; i <= mid; i ++){
b[s[i]] +=d[i];
b[t[i] + 1] -=d[i];
}
for(int i = 1; i <= n; i ++){
b[i] += b[i - 1];
if(b[i] > w[i]) return false ;
}
return true ;
}
}
2 管道
因为题目要求最早的时间 所以最早时间之后的条件也满足,顺序增长,可以想到二分来做,并且有范围之间的关系,可能会用到区间合并。
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class Main{
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static final int N = (int) 1e5+10;
static int len,n;
static int[] l = new int[N];
static int[] s = new int[N];
public static void main(String[] args) throws IOException {
//标准输入
String[] s1 = br.readLine().split(" ");
n = Integer.parseInt(s1[0]);
len = Integer.parseInt(s1[1]);
for(int i = 1; i <= n; i ++){
String[] str2 = br.readLine().split(" ");
l[i] = Integer.parseInt(str2[0]);
s[i] = Integer.parseInt(str2[1]);
}
//二分
int l = 0, r = 2*len;
while(l < r){
int mid = (int)((long)l+(r-l)/2);
if(check(mid)) r = mid;
else l = mid + 1;
}
System.out.println(r);
}
static boolean check(int mid){
PII[] res = new PII[N];
int index = 0;
for(int i = 1; i <=n; i ++){
if(s[i] > mid) continue;//因为题目中要求ti >= si 时才满足 所以 不满足的时候直接跳过
//将所有的区间都记录下来
int x = l[i] - mid +s[i];
int y = l[i] + mid - s[i];
res[index++] = new PII(Math.max(1,x),Math.min(len,y));
/*
* 需要跟1 的大小进行对比,因为 我们要求的是最早的时间 每一个管道都要被遍历到,所以 1 就是小的范围边界
* 同时右边界又要跟 最大的范围长度进行比较;
*/
}
Arrays.sort(res,0,index); //根据左端点的大小进行排序
if(res[0].x > 1) return false; //若 最小的左端点比 1即最左边的边界大,那么就不满足 遍历到所有的管道 那么就寻找更晚的时间
if(index == 0) return false; //若为空 说明mid 时间太小 需要找更大的时间
int ed = res[0].y;
for(int i = 1; i < index; i ++){
if(res[i].x -ed <= 1) ed = Math.max(ed,res[i].y);
else break;//中间的间隔若大于1 则说明不连接 那么直接跳出去 与len长度进行比较
}
return ed == len; //若两者的长度刚好相等 返回true 继续寻找更早的时间
}
}
class PII implements Comparable<PII>{
int x,y;
public PII(int x,int y){
this.x = x;
this.y = y;
}
@Override
public int compareTo(PII o){
return Integer.compare(x,o.x);
}
}