4378. 选取数对
题目链接
4378. 选取数对
给定一个长度为 \(n\) 的整数数列 \(a_{1}, a_{2}, \ldots, a_{n}\) 。
请你选择 \(k\) 个数对 \(\left[l_{1}, r_{1}\right],\left[l_{2}, r_{2}\right], \ldots,\left[l_{k}, r_{k}\right]\) ,要求所选数对满足:
- \(1 \leq l_{1} \leq r_{1}<l_{2} \leq r_{2}<\ldots<l_{k} \leq r_{k} \leq n_{\text {。 }}\)
- 对于 \(1 \leq i \leq k\) , \(r_{i}-l_{i}+1=m\) 均成立。
- 设 \(s u m=\sum_{i=1}^{k} \sum_{j=l_{i}}^{r_{i}} a_{j}\) , sum 的值应尽可能大。
请你输出 \(sum\) 的最大可能值。
输入格式
第一行包今三整数 \(n, m, k_{\text {。 }}\)
第二行包含 \(n\) 个整数 \(a_{1}, a_{2}, \ldots, a_{n}\) 。
输出格式
一个整数,表示 \(s u m\) 的最大可能值。
数据范围
前 \(6\) 个测试点满足 \(1 \leq m \times k \leq n \leq 20\) 。
所有测试点满足 \(1 \leq m \times k \leq n \leq 5000 , 0 \leq a_{i} \leq 10^{9}\) 。
输入样例1:
5 2 1
1 2 3 4 5
输出样例1:
9
输入样例2:
7 1 3
2 10 7 18 5 33 0
输出样例2:
61
解题思路
dp
- 状态表示:\(f[i][j]\) 表示前 \(i\) 个数,选了 \(j\) 对区间的最大区间和
- 状态计算:\(f[i][j]=max(f[i-1][j],f[i-m][j-1]+s[i]-s[i-m])\)
分析:第 \(i\) 个数要么在区间内要么不在
- 时间复杂度:\(O(nk)\)
代码
// Problem: 选取数对
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/4381/
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=5005;
int n,m,k,f[N][N],s[N];
int main()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
{
cin>>s[i];
s[i]+=s[i-1];
}
for(int i=m;i<=n;i++)
for(int j=1;j<=k;j++)
f[i][j]=max(f[i-1][j],f[i-m][j-1]+s[i]-s[i-m]);
cout<<f[n][k];
return 0;
}