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;
}