E. Maximum Monogonosity
E. Maximum Monogonosity
You are given an array of length and an array of length . The cost of a segment , , is defined as .
Recall that two segments , , and , , are non-intersecting if one of the following conditions is satisfied: or .
The length of a segment , , is defined as .
Find the maximum possible sum of costs of non-intersecting segments , , whose total length is equal to .
Input
Each test consists of multiple test cases. The first line contains a single integer — the number of sets of input data. The description of the test cases follows.
The first line of each test case contains two integers and () — the length of array and the total length of segments.
The second line of each test case contains integers () — the elements of array .
The third line of each test case contains integers () — the elements of array .
It is guaranteed that the sum of over all test case does not exceed .
Output
For each test case, output a single number — the maximum possible sum of costs of such segments.
Example
input
5 4 4 1 1 1 1 1 1 1 1 3 2 1 3 2 5 2 3 5 1 1 2 3 4 5 1 2 3 4 5 7 2 1 3 7 6 4 7 2 1 5 3 2 7 4 5 4 2 17 3 5 8 16 2 5 9
output
0 10 0 16 28
Note
In the first test case, the cost of any segment is , so the total cost is .
In the second test case, we can take the segment with a cost of and the segment with a cost of to get a total sum of . It can be shown that this is the optimal solution.
In the third test case, we are only interested in segments of length , and the cost of any such segment is .
In the fourth test case, it can be shown that the optimal sum is . For example, we can take the segments and .
解题思路
最直接的dp做法还是很容易想到的,定义状态表示从前个数中选出了总长度为且互不相交的区间的所有方案中的最大值。根据以第个数为右端点的区间长度进行状态划分,因此状态转移方程就是
可以发现整个dp的时间复杂度是,因此需要对状态表示或状态转移进行优化。当时想着推状态转移的式子然后找规律再结合数据结构来优化,结果发现好像不行,至少我没有做出来。然后看题解发现是对状态转移方程进行改写然后再优化,这个我肯定是想不到了。
对于,其实是等价于
即我们只需对这中组合求最大值即可,因此状态转移方程可以改写成如下形式:
可以发现,状态总是通过转移得到,而,即只要满足状态第一维减去第二维等于,那么就可以转移到。形象点理解的话,可以把个状态看作是一个矩阵,表示矩阵中第行第列的元素,那么就可以从其所在的对角线之上的所有格子(状态)转移过来,如下图:
例如状态就可以从,,转移过来。这有点类似于从某个前缀转移得到,不过在这里是斜线的前缀。一样的,我们可以用来代表某条斜线,然后分别维护每条斜线关于,,,的前缀最大值,这样在状态转移时就可以降到。
AC代码如下,时间复杂度为:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 6 const int N = 3010; 7 8 int a[N], b[N]; 9 LL f[N][N], g[N][4]; 10 11 void solve() { 12 int n, m; 13 scanf("%d %d", &n, &m); 14 for (int i = 1; i <= n; i++) { 15 scanf("%d", a + i); 16 } 17 for (int i = 1; i <= n; i++) { 18 scanf("%d", b + i); 19 } 20 for (int i = 0; i <= n; i++) { 21 for (int j = 0; j <= m; j++) { 22 f[i][j] = -0x3f3f3f3f3f3f3f3f; 23 } 24 for (int j = 0; j < 4; j++) { 25 g[i][j] = -0x3f3f3f3f3f3f3f3f; 26 } 27 } 28 f[0][0] = 0; 29 for (int i = 0; i <= n; i++) { 30 for (int j = 0; j <= min(i, m); j++) { 31 int k = i - j; 32 if (i) { 33 f[i][j] = f[i - 1][j]; 34 f[i][j] = max(f[i][j], a[i] - b[i] + g[k][0]); 35 f[i][j] = max(f[i][j], a[i] + b[i] + g[k][1]); 36 f[i][j] = max(f[i][j], -a[i] - b[i] + g[k][2]); 37 f[i][j] = max(f[i][j], -a[i] + b[i] + g[k][3]); 38 } 39 g[k][0] = max(g[k][0], f[i][j] + a[i + 1] - b[i + 1]); 40 g[k][1] = max(g[k][1], f[i][j] - a[i + 1] - b[i + 1]); 41 g[k][2] = max(g[k][2], f[i][j] + a[i + 1] + b[i + 1]); 42 g[k][3] = max(g[k][3], f[i][j] - a[i + 1] + b[i + 1]); 43 } 44 } 45 printf("%lld\n", f[n][m]); 46 } 47 48 int main() { 49 int t; 50 scanf("%d", &t); 51 while (t--) { 52 solve(); 53 } 54 55 return 0; 56 }
参考资料
Codeforces Round #892 (Div. 2) Editorial:https://codeforces.com/blog/entry/119287
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17629372.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
2022-08-14 子数组异或和