Codeforces Round #267 (Div. 2)(前缀和+二维dp)

C. George and Job

cf原题目地址
vj地址
在这里插入图片描述
在这里插入图片描述

题意:

给你一个数组,要求你找出最大的k段 长度为m的区间和并相加。

思路:

数据不大可以二维dp

  1. dp【i】【j】。i: 当前位置, j 表示有几段和。
  2. 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);
    }
    }

反思

  1. 一开始的转移时不严谨,只开了一维,没考虑位置的影响,
  2. 第k个只能从前面的i-k的位置递推过来。不能简简单单的从之前的dp【j-1】递推
  3. 因为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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章