题目描述
新款手机 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(1\leq(m×k)\leq n\leq5000)$ , 第2行读入 n 个数 p_1,p_2,…,p_n
输出格式
输出1个整数,代表可以取到的最大值
输入输出样例
输入样例#1: 复制
0 0 5 2 1 1 2 3 4 5输出样例#1: 复制
0 0 9输入样例#2: 复制
0 0 7 1 3 2 10 7 18 5 33 0输出样例#2: 复制
0 0 61思路
前缀和 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\n",f[n][k]);
return 0;
}