Educational Codeforces Round 69 (Rated for Div. 2) D. Yet Another Subarray Problem
题意:
求\(\sum_{i=l}^{r}-k\lceil\frac{r-l+1}{m}\rceil\)的最小值,\(n\leq 3*10^5,m\leq 10\)。
思路:
因为\(m\)很小,那么对于一段区间,中间部分可以划分为多个长度为\(m\)的区间,两端都长度不超过\(m\)。
所以令\(dp(i)\)表示以\(i\)为终点的区间最小值,那么一种情况是它作为区间终点,另一种情况就是其作为中间的一段,分情况转移即可。
代码如下:
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N = 3e5 + 5;
int n, m, k;
ll a[N], sum[N];
ll dp[N];
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> m >> k;
for(int i = 1; i <= n; i++) cin >> a[i], sum[i] = sum[i - 1] + a[i];
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= min(m, i); j++) {
dp[i] = max(dp[i], sum[i] - sum[i - j] - k);
}
if(i >= m) dp[i] = max(dp[i], dp[i - m] + sum[i] - sum[i - m] - k);
}
ll ans = 0;
for(int i = 1; i <= n; i++) ans = max(ans, dp[i]);
cout << ans;
return 0;
}
还有一种算法,因为余数比较小,所以就以\(i\)%\(m\)的值分类,然后对于每个余数维护一个前缀最小值。
更新答案时用目前前缀减去所维护的最小值就行了。