loj10177. 「一本通 5.5 例 3」修剪草坪
思路:
状态:dp【i】【0】表示前i个元素,i号元素不取的情况,dp【i】【1】表示前i个元素,第i个取的情况。
·方程:dp【i】【1】=max【i-m <= j < i】(dp【j】【0】 - sum【j】) + sum【i】
dp【i】【0】=max(dp【i-1】【0】, dp【i-1】【1】);
优化:单调队列
#include<cstdio> #include<iostream> #include<cstring> using namespace std; const int maxn = 200010; inline int qread(){ register int ch = getchar(), flag = 0, x = 0; while(ch < '0' || ch > '9') {if(ch == '-') flag = 1; ch = getchar();} while(ch >= '0' && ch <= '9') x = 10 * x + ch - 48, ch = getchar(); return flag ? -x : x; } long long qu[maxn]; int head = 1, tail, pos[maxn]; long long sum[maxn]; long long data[maxn]; long long dp[maxn][2]; int n, m; void dpmax(){ for(int i = 1; i <= n; ++i){ while(pos[head] < i - m + 1 && head <= tail) head++; while(qu[tail] <= dp[i - 1][0] - sum[i - 1] && head <= tail) tail--; pos[++tail] = i; qu[tail] = dp[i - 1][0] - sum[i - 1]; dp[i][1] = qu[head] + sum[i]; dp[i][0] = max(dp[i - 1][0], dp[i - 1][1]); } } int main(void){ n = qread(), m = qread(); for(int i = 1; i <= n; ++i) data[i] = qread(); for(int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + data[i]; dpmax(); cout << max(dp[n][0], dp[n][1]) << endl; return 0; }