【题解】codeforces 467C George and Job dp

题目描述

新款手机 iTone6 近期上市,George 很想买一只。不幸地,George 没有足够的钱,所以 George 打算当一名程序猿去打工。现在George遇到了一个问题。 给出一组有 n 个整数的数列p_1,p_2,…,p_n ,你需要挑出 k 组长度为 m 的数,要求这些数互不重叠 即 [l_{1},r_{1}],[l_{2},r_{2}],…,[l_{k},r_{k}] (1<=l_{1}<=r_{1}<l_{2}<=r_{2}<…<l_{k}<=r_{k}<=n; r_{i}-l_{i}+=m) 使选出的数的和值最大,请你帮助George码出这份代码

输入输出格式

输入格式

第1行读入3个整数 n , m , $k(1leq(m×k)leq nleq5000)$ , 第2行读入 n 个数 p_1,p_2,…,p_n

输出格式

输出1个整数,代表可以取到的最大值

输入输出样例

输入样例#1: 复制

输出样例#1: 复制

输入样例#2: 复制

输出样例#2: 复制

思路

前缀和 dp

  • $sum[i]$表从$p_{i-m+1}$到$p_{i}$共m个数的前缀和
  • $dp[i][j]$表从1~i中取j个区间可以得到的最大值

转移方程
$f[i][j]=max(f[i][j],f[i-m][j-1]+sum[i])$

代码

#include<cmath>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define re register int
#define ll long long
using namespace std;
inline int read(){
	int x=0,w=1;
	char ch=getchar();
	while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
	if(ch=='-') w=-1,ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-48,ch=getchar();
	return x*w;
}
int n,m,k; 
int g[1000005], r[100005]; 
ll f[5005][5001],sum[5005];
int main() {
    n=read(),m=read(),k=read();
    for(re i=1;i<=n;++i) {
    	g[i]=read();
    	if(i<=m) sum[i]=sum[i-1]+g[i];
    	if(i>m) sum[i]=sum[i-1]-g[i-m]+g[i];
    }
    for(re i=1;i<=n;++i) 
    	for(re j=1;j<=k;++j) {
    		f[i][j]=f[i-1][j];
    		if(i>=m&&f[i-m][j-1]!=-1) f[i][j]=max(f[i][j],f[i-m][j-1]+sum[i]); 
    	}
    printf("%lld
",f[n][k]);
	return 0;
}

原文地址:https://www.cnblogs.com/bbqub/p/cf_467c.html