选取数对
选取数对
给定一个长度为 的整数数列 。
请你选择 个数对 ,要求所选数对满足:
- 。
- 对于 , 均成立。
- 设 , 的值应尽可能大。
请你输出 的最大可能值。
输入格式
第一行包含三个整数 。
第二行包含 个整数 。
输出格式
一个整数,表示 的最大可能值。
数据范围
前 个测试点满足 。
所有测试点满足 ,。
输入样例1:
5 2 1 1 2 3 4 5
输出样例1:
9
输入样例2:
7 1 3 2 10 7 18 5 33 0
输出样例2:
61
解题思路
这题是从若干个长度为的区间里面选择个,求选择的这个区间和的最大值,并且这个区间两两不能有交集。
这题是用动态规划做的。
AC代码如下:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 typedef long long LL; 7 8 const int N = 5010; 9 10 LL s[N], f[N][N]; 11 12 int main() { 13 int n, m, k; 14 scanf("%d %d %d", &n, &m, &k); 15 for (int i = 1; i <= n; i++) { 16 int val; 17 scanf("%d", &val); 18 s[i] = s[i - 1] + val; 19 } 20 21 for (int i = 1; i <= n; i++) { 22 for (int j = 1; j <= k; j++) { 23 f[i][j] = f[i - 1][j]; 24 if (i - m >= 0) f[i][j] = max(f[i][j], f[i - m][j - 1] + s[i] - s[i - m]); 25 } 26 } 27 28 printf("%lld", f[n][k]); 29 30 return 0; 31 }
这种划分方式的时间复杂度为,会超时,因此需要优化。
我们可以发现,当固定的时候,那么的起点也就是最小值就是固定不变。枚举,每当加,那么的最大值就增加,也就是只会增加多一个。又因为我们是找这个区间内的的最大值,因此我们可以用一个变量来维护这个动态区间的最大值。
比如说,如果要知道的最大值,那么我们需要划分集合,的取值范围为,我们要求的是所有的中的最大值,然后加上。对于,这时的取值范围为,一样要求所有的中的最大值,我们可以发现与相比,就多求了一个,这意味着前面的枚举是重复的。因此我们可以开一个变量来动态维护之前的数的最大值,这样就不用每次都从头枚举。
或者可以这样想,因为每次枚举都是从开始往前枚举,因此我们可以把定义为右端点不超过,且选择了个区间的所有合法方案的集合,存的就是最小值,这就变成上面第一种的划分方式了(不合法方案被赋值为负无穷,不会影响取最大值)。
AC代码如下:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 typedef long long LL; 7 8 const int N = 5010; 9 10 LL s[N], f[N][N]; 11 12 int main() { 13 int n, m, k; 14 scanf("%d %d %d", &n, &m, &k); 15 for (int i = 1; i <= n; i++) { 16 int val; 17 scanf("%d", &val); 18 s[i] = s[i - 1] + val; 19 } 20 21 for (int j = 1; j <= k; j++) { // 先枚举选择的区间个数 22 LL maxf = 0; 23 for (int i = j * m; i <= n; i++) { // 再枚举区间右端点 24 maxf = max(maxf, f[i - m][j - 1] + s[i] - s[i - m]); // 每枚举一个新的右端点,加入并动态维护所求区间的最大值 25 f[i][j] = maxf; 26 } 27 } 28 29 LL ret = 0; 30 for (int i = m; i <= n; i++) { 31 ret = max(ret, f[i][k]); 32 } 33 printf("%lld", ret); 34 35 return 0; 36 }
另外一种集合的定义如下:所有选择了个区间且最后一个区间的右端点为的合法方案的集合。划分方式和上面的一样。
AC代码如下:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 typedef long long LL; 7 8 const int N = 5010; 9 10 LL s[N], f[N][N]; 11 12 int main() { 13 int n, m, k; 14 scanf("%d %d %d", &n, &m, &k); 15 for (int i = 1; i <= n; i++) { 16 int val; 17 scanf("%d", &val); 18 s[i] = s[i - 1] + val; 19 } 20 21 for (int i = 1; i <= k; i++) { 22 LL maxf = 0; 23 for (int j = i * m; j <= n; j++) { 24 maxf = max(maxf, f[i - 1][j - m] + s[j] - s[j - m]); 25 f[i][j] = maxf; 26 } 27 } 28 29 LL ret = 0; 30 for (int i = m; i <= n; i++) { 31 ret = max(ret, f[k][i]); 32 } 33 printf("%lld", ret); 34 35 return 0; 36 }
参考资料
AcWing 4378. 选取数对(AcWing杯 - 全国联赛):https://www.acwing.com/video/3743/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16035240.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效