E. Cashback
题目大意:
思路解析:
如果c==1,那么无论如何 答案都为0.
如果c!=1,我们考虑如果最优答案有一段区间长度小于c,那么它对答案的贡献值,等于将这个区间划分为长度为1的多个小段,
如果有一段区间长度大于c小于2 * c,那么相当于在里面找到需要删除的数在其旁划分出一个长度为c的区间,其余部分都划分长度为1的小区间。
如果有区间长度等于2*c,那么把c划分为两个长度为c的区间,只能一个区间删除一个对于这个区间长度为2*c才是等价的(其余情况,划分为单个长度为c的区间对于整体答案更加优秀)。说明无论如何将整体划分长度为1或者长度为n的区间是最优选择。
代码实现:
import java.io.*;
import java.math.BigInteger;
import java.util.*;public class Main {public static void main(String[] args) throws IOException {int n = input.nextInt();int c = input.nextInt();int[] arr = new int[n + 1];int[] min = new int[n + 1];long[] dp = new long[n + 1];long[] sum = new long[n + 1];for (int i = 1; i <= n; i++) {arr[i] = input.nextInt();sum[i] = sum[i - 1] + arr[i];}LinkedList<Integer> list = new LinkedList<>();for (int i = 1; i <= Math.min(c, n); i++) {if (list.isEmpty()){list.add(i);}else{int j = list.getLast();if(arr[j] <= arr[i]){list.add(i);}else{while (arr[list.getLast()] > arr[i]){list.removeLast();if (list.isEmpty()) break;}list.add(i);}}min[i] = arr[list.getFirst()];}for (int i = c + 1; i <= n; i++) {while (!list.isEmpty() && list.getFirst() <= i - c) list.remove();if (list.isEmpty()){list.add(i);}else{int j = list.getLast();if(arr[j] <= arr[i]){list.add(i);}else{while (arr[list.getLast()] > arr[i]){list.removeLast();if (list.isEmpty()) break;}list.add(i);}}min[i] = arr[list.getFirst()];}for (int i = 1; i <= n; i++) {if (i >= c)dp[i] = Math.min(dp[i - 1] + arr[i], dp[i - c] + sum[i] - sum[i - c] - min[i]);else dp[i] = dp[i - 1] + arr[i];}out.println(dp[n]);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());}}}