C. George and Job
题意:
给你一个数组,要求你找出最大的k段 长度为m的区间和并相加。
思路:
数据不大可以二维dp
- dp【i】【j】。i: 当前位置, j 表示有几段和。
- for(int i=m, i<=n; i++)
{
ll tmp;
tmp=pre[i]-pre[i-m];
for(int j=min(i/m,k);j>=1; j–)//枚举的段数,不能超过当前的i/m,也不能大于k段,因为最多只有k段
{
dp[i][j]=max(dp[i-1][j],dp[i-m][j-1]+tmp);
}
}
反思
- 一开始的转移时不严谨,只开了一维,没考虑位置的影响,
- 第k个只能从前面的i-k的位置递推过来。不能简简单单的从之前的dp【j-1】递推
- 因为j-1取得的最大位置可能在【i-k,i】之中,即重合了,所以要多开一维,避免重合
AC
#include <iostream>
#define For(i,x,y) for(int i=(x); i<=(y); i++)
using namespace std;
typedef long long ll;
const int maxn=5e3+10;
ll dp[maxn][maxn];
ll pre[maxn];
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int n,m,k;
cin>>n>>m>>k;
For(i,1,n)
{
ll p;
cin>>p;
pre[i]=pre[i-1]+p;
}
ll ans=0;
For(i,m,n)
{
ll tmp;
tmp=pre[i]-pre[i-m];
for(int j=min(i/m,k);j>=1; j--)
{
dp[i][j]=max(dp[i-1][j],dp[i-m][j-1]+tmp);
}
}
cout<<dp[n][k]<<endl;
return 0;
}