晾衣服
题目分析
这里出现了“最小化干燥的总时间”,那么可以考虑用二分去做。
第一阶段二段性分析
假设当前需要耗费的时间为mid分钟,如果mid分钟内可以烘干这些衣服,那么我们可以确定右边界大于mid的区间一定也可以。但是此时我需要找的是最短时间,那么mid一定比大于mid的值更小,所以大于mid的值我就不用管了,也就是我可以确定我能够舍弃掉mid右边的值。我还想要确定比mid更小的值是否也满足条件,所以我要在mid的左边继续二分。
if(check(mid)) {r = mid;}//因为mid是符合条件的,所以我要留着它,而不是r=mid-1
假设当前需要耗费的时间为mid分钟,如果mid分钟内不可以烘干这些衣服,那么我们可以确定右边界小于mid的区间一定也不可以。所以小于mid的值我就不用管了,也就是我可以确定我能够舍弃掉mid左边的值。我还想要找比mid更大的值是否可以满足条件,所以我要在mid的右边继续二分。
else {l = mid + 1;}//因为mid是不符合条件的,所以我不要留着它,而不是l=mid
综上该题满足二段性,可以用二分,二分的板子就不说了,接下来说一下check函数如何写。
第二阶段写check函数
check(u)要实现的作用是检查能否在mid分钟内烘干这些衣服。对于一个衣服的湿度a[i],如果他大于mid,就需要使用烘干机,使用的时间是(a[i]-mid)/(k-1)。因为烘干衣服不足1分钟也要按一分钟算,所以这里要上取整。
这里为什么是k-1呢?我们要保证在mid分钟内烘干,因为衣服每一分钟湿度都会减1,如果我把衣服放在烘干机上湿度会减k,那么放在烘干机和不放在烘干机上会比原来多减了k-1。我们要注意的是,烘干机使用的总时间不能超过mid。
假设我只有一个衣服需要烘干,如果mid=3,a[i]=10,k=3。a[i]-mid=10-3=7。如果是7/3=3。这样看mid等于3是可以的,但是我把烘干机全用在这一个衣服上所需要的烘干时间是10/3=4>mid=3,明确不可以在3分钟内烘干该衣服。所以我这里应该是7/2=4,此时可以判断出来不可以在3分钟内烘干该衣服。check函数如下,
static boolean check(int mid) {long s = 0;for (int i = 0; i < n; i++) {if (a[i] > mid) {s += (long)(a[i] - mid + k - 2) / (k - 1);}}return s <= mid;}
第三阶段二分范围确定
烘干的时间最长就是不使用烘干机,自然风干需要a[i]分钟,而a[i]最大是1e9,所以l=0,r=1e9。
注意一个特殊情况,如果k=1,那么其实烘干机有和没有都一样,自然风干所需要的时间就是所有衣服中最大的湿度。
for (int i = 0; i < n; i++) {a[i] = sc.nextInt();maxV = Math.max(maxV, a[i]);
}
k = sc.nextInt();
if (k == 1) {System.out.println(maxV);return;
}
题目代码
import java.util.Scanner;
public class Main {static int N = 100010;static int n, k;static int[] a = new int[N];public static void main(String[] args) {Scanner sc = new Scanner(System.in);n = sc.nextInt();int maxV = 0;for (int i = 0; i < n; i++) {a[i] = sc.nextInt();maxV = Math.max(maxV, a[i]);}k = sc.nextInt();if (k == 1) {System.out.println(maxV);return;}int l = 1, r = (int) 1e9;int res = 0;while (l < r) {int mid = (l + r)/2;if (check(mid)) {r = mid;} else {l = mid + 1;}}System.out.println(l);}static boolean check(int mid) {long s = 0;for (int i = 0; i < n; i++) {if (a[i] > mid) {s += Math.ceil((a[i]-mid)*1.0 / (k - 1));}}return s <= mid;}
}