算法分析
二分 + 滑动窗口
- 1、给定某个长度,若该长度满足条件,就变长继续观察,不满足则变短继续观察,直到找到最小符合的长度值,因此使用二分
- 2、
check
函数中,给定最长的空题段的长度是mid
,求出满足题意的花费时间最小值res
,判断res <= t
是否成立
- 3、由于最长的空题段的长度是
k = mid
,传进check()函数的变量是k
,因此滑动窗口的长度是mid + 1
,
以i
结尾的f[i]
,滑动窗口的区间是[i - (k + 1),i - 1]
,单调队列维护的是该区间的最小值,由于滑动窗口不包含i
,因此f[i]
需要在while
上方进行更新
时间复杂度 $O(nlogn)$
参考文献
算法提高课
Java 代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static int N = 50010;
static int[] q = new int[N];
static int[] a = new int[N];
static int n, m;
static int[] f = new int[N];
static boolean check(int k)
{
int hh = 0,tt = 0;
int res = 0x3f3f3f3f;
for(int i = 0;i <= n;i ++)
{
if(hh <= tt && q[hh] < i - (k + 1)) hh ++;
if(hh <= tt) f[i] = f[q[hh]] + a[i];//需要将0实现进入队列
while(hh <= tt && f[q[tt]] >= f[i]) tt --;
q[++ tt] = i;
if(i >= n - k) res = Math.min(res, f[i]);
}
return res <= m;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
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 ++)
{
a[i] = Integer.parseInt(s2[i - 1]);
}
int l = 0,r = n;
while(l < r)
{
int mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
System.out.println(l);
}
}
小呆呆大神 每次被这些下标+1 -1 啥的烦死了 请问你是怎么解决的呢
我是思路不够清晰的时候就多画图,看图理解是要
+1
还是-1
,确保思路清晰,想多几次熟练了就知道+1
还是-1
了hh好滴