题面
在某个世界里,一周有 $ N $ 天。
有一个工厂,为了最大化工人的产出,决定合理安排工作日和休息日。
他们根据统计,发现:
对于每个工作日,如果最近的一个休息日距离他有 $ i $ 天,则产出为 $ A_i $ ;
对于每个休息日,产出为 0。
问一周的最大产出。
思路
dp!dp!dp!
设 $ f_i $ 为前 $ i $ 天的最大总产出(第 $ i $ 天是假期),那么我们遍历 $ i \in 1 \ldots n $ ,
设 $ j $ 为假期与假期间的长度,则可得转移方程 $ f_i = f_{i - j - 1} + \operatorname{calc} (j) $ ,其中 $ \operatorname{calc} (j) $ 表示长度 $ j $ 的一段的总产出。
$ \operatorname{calc} $ 函数可以直接用前缀和求。
那么就完了。
代码
// Problem: E - Work or Rest
// Contest: AtCoder - AtCoder Beginner Contest 285
// URL: https://atcoder.jp/contests/abc285/tasks/abc285_e
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
long long a[10005];
long long pre[10005];
long long f[10005];
long long calc(long long len) {
if (len & 1) {
return pre[len / 2] + pre[len / 2 + 1];
} else {
return pre[len / 2] + pre[len / 2];
}
}
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
pre[i] = pre[i - 1] + a[i];
a[i + n] = a[i];
}
for (int i = n + 1; i <= 2 * n; i++) {
pre[i] = pre[i - 1] + a[i];
}
long long ans = -0x3f3f3f3f3f3f3f3fll;
for (int i = 2; i <= n; i++) {
f[i] = -0x3f3f3f3f3f3f3f3fll;
for (int j = 0; j < i; j++) {
f[i] = max(f[i], f[i - j - 1] + calc(j));
}
}
printf("%lld", f[n]);
}
标签:pre,ABC,产出,len,long,calc,285
From: https://www.cnblogs.com/AProblemSolver/p/17055802.html