Link
题意:
在一天 \(n\) 个小时中取 \(b\) 个小时,使权值和最大,\(b\) 个小时可分成若干段,每段的第一个小时的权值不计入总和,第 \(n\) 个小时与第一个小时相连
思路:
记 \(f[i][j][0]\) 为前 \(i\) 个小时中睡了 \(j\) 个小时且第 \(i\) 个小时不在睡,\(f[i][j][1]\) 为前 \(i\) 个小时中睡了 \(j\) 个小时且第 \(i\) 个小时在睡
转移方程:
\( \begin{cases} f[i][j][0]=\max(f[i-1][j][0],f[i-1][j][1]) \\ f[i][j][1]=\max(f[i-1][j-1][0],f[i-1][j-1][1]+w[i]) \end{cases} \)
因为首尾相连,所以第 \(n\) 个小时会影响第一个小时
当第 \(n\) 个小时没有睡:\(f[1][0][0]=f[1][1][1]=0\),结果为 \(f[n][b][0]\)
当第 \(n\) 个小时在睡:\(f[1][0][0]=0,f[1][1][1]=w[1]\),结果为 \(f[n][b][1]\)
取最大值
代码:
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define fi first
#define se second
typedef long long ll;
typedef pair<int,int> pii;
const int N=4000;
int w[N];
int f[N][2];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n,b;
cin>>n>>b;
for(int i=1;i<=n;i++) cin>>w[i];
memset(f,0xc0,sizeof f);
f[0][0]=f[1][1]=0;
for(int i=2;i<=n;i++)
for(int j=min(i,b);j>=0;j--) {
f[j][0]=max(f[j][0],f[j][1]);
if(j) f[j][1]=max(f[j-1][0],f[j-1][1]+w[i]);
}
int res=f[b][0];
memset(f,0xc0,sizeof f);
f[0][0]=0,f[1][1]=w[1];
for(int i=2;i<=n;i++)
for(int j=min(i,b);j>=0;j--) {
f[j][0]=max(f[j][0],f[j][1]);
if(j) f[j][1]=max(f[j-1][0],f[j-1][1]+w[i]);
}
res=max(res,f[b][1]);
cout<<res<<endl;
return 0;
}