目录
D. Blocking Elements
题目大意:
思路解析:
将整个长度n的序列分为多个部分,求每个部分的和与分割点的和的最大值的最小值,那其实可以看作是否有每个部分小于等于m的分割方案,如果找到一个分割方案,说明当前最大值为m,那么可以发现这样定义之后,答案满足单调性,可以使用二分查找最小的m。
dp[i] 表示第i个点作为分割点,且i-n个数部分和满足小于等于m的定义,假设 i+1 <-> j 的和小于等于m,那么上一个划分点可以为j,j-1,.......,i+2,i+1.则dp[i] = Math.min(dp[k] + arr[i], dp[i]), i+1<=k<=j+1,这个又是某连续区间求最小值,可以使用单调队列维护,当前区间最小。
然后通过dp来维护每个点作为分割点的答案,如果能找到一个dp[i]<=m并且1<->i-1的和也小于等于m,则找到了一种分割方法。
代码实现:
import java.io.*;
import java.math.BigInteger;
import java.util.*;
public class A {
public static void main(String[] args) throws IOException {
int t = input.nextInt();
long inf = Long.MAX_VALUE;
for (int o = 0; o < t; o++) {
int n = input.nextInt();
int[] arr = new int[n + 1];
long sum = 0;
for (int i = 1; i <= n; i++) {
arr[i] = input.nextInt();
sum += arr[i];
}
long l = 0;
long r = sum;
long ans = 0;
while (l <= r) {
long mid = (l + r) >> 1;
long[] dp = new long[n + 2];
Arrays.fill(dp, inf);
dp[n + 1] = 0;
int q = n + 1;
long tot = 0;
LinkedList<Integer> list = new LinkedList<>();
list.add(n + 1);
for (int i = n; i >= 1 ; i--) {
while (tot > mid){
tot -= arr[q - 1];
while (!list.isEmpty() && list.getFirst() >= q) list.removeFirst();
q--;
}
dp[i] = dp[list.getFirst()] + arr[i];
while (!list.isEmpty() && dp[list.getLast()] >= dp[i]) list.removeLast();
list.add(i);
tot += arr[i];
}
int yes = 0;
tot = 0;
for (int i = 1; i <= n; i++) {
if (tot <= mid && dp[i] <= mid){
yes = 1;
break;
}
tot += arr[i];
}
if (yes == 1){
ans = mid;
r = mid - 1;
}else{
l = mid + 1;
}
}
out.println(ans);
}
out.flush();
out.close();
br.close();
}
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
static Input input = new Input(System.in);
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static class Input {
public BufferedReader reader;
public StringTokenizer tokenizer;
public Input(InputStream stream) {
reader = new BufferedReader(new InputStreamReader(stream), 32768);
tokenizer = null;
}
public String next() {
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
try {
tokenizer = new StringTokenizer(reader.readLine());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}
public String nextLine() {
String str = null;
try {
str = reader.readLine();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
return str;
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
public Double nextDouble() {
return Double.parseDouble(next());
}
public BigInteger nextBigInteger() {
return new BigInteger(next());
}
}
}