选元素
选元素
给定一个长度为 的整数序列 。
请你从中挑选 个元素,要求:
- 原序列中的每一个长度为 的连续子序列都至少包含一个被选中的元素。
- 满足条件 的前提下,所选 个元素的相加之和应尽可能大。
输出最大可能和。
输入格式
第一行包含三个整数 。
第二行包含 个整数 。
输出格式
如果无法满足题目要求,则输出 。
否则,输出一个整数,表示所选元素的最大可能和。
数据范围
前三个测试点满足 。
所有测试点满足 。
输入样例1:
5 2 3 5 1 3 10 1
输出样例1:
18
输入样例2:
6 1 5 10 30 30 70 10 10
输出样例2:
-1
输入样例3:
4 3 1 1 100 1 1
输出样例3:
100
解题思路
首先可以发现这题的选法有很多,大概是指数级别的。例如,如果,那么我们的选法就有种,那么这题大概率用动态规划或者贪心来做。
最后的答案应该是,因为最后一个数不一定会被选,而且因为要求长度为的子序列中至少要有个数被选,因此最远可以选到第个数。
时间复杂度为,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 = 210; 9 10 LL a[N], f[N][N]; 11 12 int main() { 13 int n, k, m; 14 scanf("%d %d %d", &n, &k, &m); 15 for (int i = 1; i <= n; i++) { 16 scanf("%d", a + i); 17 } 18 19 // 处理边界 20 memset(f, -0x3f, sizeof(f)); 21 // 这里处理f(i, 1)的情况,也可以直接f(0, 0) = 0 22 for (int i = 1; i <= k; i++) { 23 f[i][1] = a[i]; 24 } 25 26 for (int i = 1; i <= n; i++) { 27 for (int j = 1; j <= m; j++) { 28 for (int u = max(1, i - k); u < i; u++) { 29 f[i][j] = max(f[i][j], f[u][j - 1] + a[i]); 30 } 31 } 32 } 33 34 LL ret = -1; 35 for (int i = n; i > n - k; i--) { 36 ret = max(ret, f[i][m]); 37 } 38 printf("%lld", ret); 39 40 return 0; 41 }
在进行状态计算的时候,可以发现对于固定的,每次都是从一个长度为的窗口中求一个最大值,即枚举的范围是。因此可以用单调队列进行优化,先枚举,再枚举,每次维护长度为的窗口中的最大值。
时间复杂度为,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 = 210; 9 10 LL a[N], f[N][N]; 11 LL q[N], hh, tt = -1; 12 13 int main() { 14 int n, k, m; 15 scanf("%d %d %d", &n, &k, &m); 16 for (int i = 1; i <= n; i++) { 17 scanf("%d", a + i); 18 } 19 20 memset(f, -0x3f, sizeof(f)); 21 for (int i = 1; i <= k; i++) { 22 f[i][1] = a[i]; 23 } 24 25 for (int j = 2; j <= m; j++) { 26 hh = 0, tt = -1; 27 for (int i = 1; i <= n; i++) { 28 if (hh <= tt && q[hh] < i - k) hh++; 29 if (hh <= tt) f[i][j] = f[q[hh]][j - 1] + a[i]; 30 while (hh <= tt && f[q[tt]][j - 1] <= f[i][j - 1]) { 31 tt--; 32 } 33 q[++tt] = i; 34 } 35 } 36 37 LL ret = -1; 38 for (int i = n; i > n - k; i--) { 39 ret = max(ret, f[i][m]); 40 } 41 printf("%lld", ret); 42 43 return 0; 44 }
参考资料
AcWing 4418. 选元素(AcWing杯 - 周赛):https://www.acwing.com/video/3859/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16247881.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效