AtCoder Beginner Contest 285 E(背包dp)

E - Work or Rest

题目大意:

给定一周有n天,其中至少有1天为休息日,其余为工作日。同时给定一个长度为n的整型数组A,对于一个工作日,它能产生的工作值为A\(_{min(x,y)}\),其中x,y表示离该工作日最近的一个休息日(前一个,后一个)的时间。
求每周工作所能获得的最大工作值。


解题思路:

我们通过举例可以发现:连续的k天工作日所能获得的工作值是固定的
例如:
给定A:10 10 1 1 1 1 1

k = 0:work\(_0\) = 0
k = 1:work\(_1\) = A\(_1\) = 10
k = 2:work\(_2\) = A\(_1\) + A\(_{min(1,2)}\) = 2*A\(_1\) = 20
k = 3:work\(_3\) = A\(_{min(1,3)}\) + A\(_2\) + A\(_{min(3,1)}\) = 2*A\(_1\) + A\(_2\) = 30
k = 4:work\(_4\) = A\(_{min(1,4)}\) + A\(_{min(2,3)}\)+A\(_{min(3,2)}\)+A\(_{min(4,1)}\) = 2*A\(_1\) + 2*A\(_2\) = 40
....
k = d: work = work\(_{d-1}\)+A\(_{(i+1)/2}\)
同时我们发现:对于一周的工作时间和休息的总和为n

所以我们考虑背包:背包的体积为n表示一周的工作时间和休息的总和
物品p = d(体积)表示1天休息+连续(d-1)天所能获得的工作值

dp[i]表示 i 天所能获得的做大工作值


代码实现:

#include<bits/stdc++.h>
using namespace std;
# define int long long
# define endl "\n"
const int N = 2e5 + 10, inf = 1e18;
int pre[N];
int a[N];
void solve() {
	int n;
	cin >> n;
	for(int i = 1;i <= n;++i) cin>>a[i];
	for(int i = 1;i <= n;++i) pre[i] = pre[i-1]+a[(i+1)/2];
//	for(int i = 1;i <= n;++i) cout<<pre[i]<<" \n"[i==n];
	vector<int> f(n+1);
	for(int i = 1;i <= n;++i){
		for(int j = 1;j <= i;++j){
			f[i] = max(f[i],f[i-j]+pre[j-1]);
		}
	}
	
	cout<<f[n]<<endl;
}
int tt;
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	tt = 1;
//	cin >> tt;
	while (tt--) solve();


	return 0;
}
posted @ 2023-01-17 19:21  empty_y  阅读(47)  评论(0)    收藏  举报