inlineintread(){ int s = 0, x = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') x = -x; ch = getchar(); } while (isdigit(ch)) { s = s * 10 + ch - '0'; ch = getchar(); } return s * x; }
/** * * 考虑 dp * 设 dp[i] 表示选择第 i 个来保证 [1, i] 合法的最小花费 * 转移方程: * dp[i] = cost[i] + min{dp[j]} (i - m <= j < i) * 后面这个 min 可以滑动窗口优化 * */
constint MAXN = 2e5 + 10;
int q1[MAXN], q2[MAXN]; int h1 = 1, t1 = 1, h2 = 1, t2 = 1; // 左闭右开
int n, m; int ss[MAXN]; int dp[MAXN];
intmain(){ n = read(); m = read(); for (int i = 1; i <= n; ++i) ss[i] = read(); for (int i = 1; i <= n; ++i) { // 队尾弹出不优的,维护单调性 while (h1 != t1 && q1[t1 - 1] >= dp[i - 1]) --t1, --t2; // 队尾入队 q1[t1++] = dp[i - 1]; q2[t2++] = i - 1; // 队头弹出过期的 while (h2 != t2 && q2[h2] < i - m) ++h1, ++h2; // 更新答案 dp[i] = ss[i] + q1[h1]; } int ans = 0x7f7f7f7f; for (int i = n - m + 1; i <= n; ++i) ans = std::min(ans, dp[i]); printf("%d\n", ans); return0; }