链接链接
题意:给一个数组,长度为 n ,现在要选择 k 段长度为 m 的不相交的子段,问最大和是多少。
思路:dp[i][k] 表示到 i 个数,选取 k 段的最大和。
有状态转移方程 dp[i][k] = max(dp[i - 1][k],dp[i - m][k - 1] + pre[i] - pre[i - m]) . 其中 pre 表示前缀和。
Code:
#include<bits/stdc++.h>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define ull unsigned LL
#define ls i << 1
#define rs (i << 1) + 1
#define fir first
#define sec second
#define CLR(a) while(!(a).empty()) a.pop()
using namespace std;
const int maxn = 5e3 + 10;
LL a[maxn],pre[maxn];
LL dp[maxn][maxn];
int main() {
int n,m,k;
while(~scanf("%d%d%d",&n,&m,&k)){
rep(i,1,n + 1){
scanf("%lld",&a[i]);
pre[i] = pre[i - 1] + a[i];
}
for(int i = 1;i <= n;++ i)
for(int j = 1;j <= i / m;++ j)
dp[i][j] = max(dp[i - 1][j],dp[i - m][j - 1] + pre[i] - pre[i - m]);
// debug(dp[n][k]);
cout << dp[n][k] << endl;
}
return 0;
}