读入$n$个整数,选取其中若干个数,最多连续取$k$个,求取到数字和的最大值
$1\le k \le n \le 100000$
感谢@oy 的贡献
一道单调队列入门题。
面对动规题,首先设计状态转移方程。令$f[i]$表示$1-i$中连取不超过$K$个数,且第$i$个数不取所能累加的最大和。
因为第$i$个数不取,所以在$i$之前一定连取了一段数。这段数的长度可能为$0-K$(注意是$0-K$而不是$1-K$,可以通过手推样例发现最优解中可能存在连着两个数不取的情况)。连取的一段数所能累加的和可以用前缀和计算。考虑边界条件后,状态转移方程如下:
$$
f[i]=\max_{i-K-1\le j \le i-1} \lbrace f[j]+s[i-1]-s[j] \rbrace
$$
由于$max$函数的循环变量是$j$,所以只与$i$相关的变量$s[i-1]$可以作为常数提出到$max$函数之外,即:
$$
f[i]=\max_{i-K-1\le j \le i-1}\lbrace f[j]-s[j]\rbrace +s[i-1]
$$
将状态转移方程化简到这样,就已经可以用单调队列进行优化了。我们可以用单调队列维护$f[j]-s[j]$的最值,在循环时将其最大值取出再加上$s[i-1]$即为$f[i]$。
如果想不到该如何操作,也可以这样理解:
$$
g[i]=f[i]-s[i]
$$
$$
f[i]=\max_{i-K-1\le j \le i-1}\lbrace g[j]\rbrace+s[i-1]
$$
由于我们定义$f[i]$是第$i$个数不取的最优解,可以强行求解$f[N+1]$(虽然它似乎没有实际意义)作为本题的最终答案。
代码如下:
1 | #include <bits/stdc++.h> |