E. Maximum Monogonosity

E. Maximum Monogonosity

You are given an array a of length n and an array b of length n. The cost of a segment [l,r], 1lrn, is defined as |blar|+|bral|.

Recall that two segments [l1,r1], 1l1r1n, and [l2,r2], 1l2r2n, are non-intersecting if one of the following conditions is satisfied: r1<l2 or r2<l1.

The length of a segment [l,r], 1lrn, is defined as rl+1.

Find the maximum possible sum of costs of non-intersecting segments [lj,rj], 1ljrjn, whose total length is equal to k.

Input

Each test consists of multiple test cases. The first line contains a single integer t (1t1000) — the number of sets of input data. The description of the test cases follows.

The first line of each test case contains two integers n and k (1kn3000) — the length of array a and the total length of segments.

The second line of each test case contains n integers a1,a2,,an (109ai109) — the elements of array a.

The third line of each test case contains n integers b1,b2,,bn (109bi109) — the elements of array b.

It is guaranteed that the sum of n over all test case does not exceed 3000.

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 0, so the total cost is 0.

In the second test case, we can take the segment [1,1] with a cost of 8 and the segment [3,3] with a cost of 2 to get a total sum of 10. It can be shown that this is the optimal solution.

In the third test case, we are only interested in segments of length 1, and the cost of any such segment is 0.

In the fourth test case, it can be shown that the optimal sum is 16. For example, we can take the segments [3,3] and [4,4].

 

解题思路

  最直接的dp做法还是很容易想到的,定义状态f(i,j)表示从前i个数中选出了总长度为j且互不相交的区间的所有方案中的最大值。根据以第i个数为右端点的区间长度进行状态划分,因此状态转移方程就是f(i,j)=max{f(i1,j), max1umin{j,k}{f(iu,ju)+|aibiu+1|+|aiu+1bi|}}(ji)

  可以发现整个dp的时间复杂度是O(nk2),因此需要对状态表示或状态转移进行优化。当时想着推状态转移的式子然后找规律再结合数据结构来优化,结果发现好像不行,至少我没有做出来。然后看题解发现是对状态转移方程进行改写然后再优化,这个我肯定是想不到了。

  对于|albr|+|arbl|,其实是等价于|albr|+|arbl|=max{blar+bral,blarbr+al,bl+ar+bral,bl+arbr+al}

  即我们只需对这4中组合求最大值即可,因此状态转移方程可以改写成如下形式:f(i,j)=max{f(i1,j), max1umin{j,k}{f(iu,ju)+|aibiu+1|+|aiu+1bi|}}=max{f(i1,j),max1umin{j,k}{f(iu,ju)aiu+1+biu+1}ai+bi,max1umin{j,k}{f(iu,ju)+aiu+1+biu+1}aibi,max1umin{j,k}{f(iu,ju)aiu+1biu+1}+ai+bi,max1umin{j,k}{f(iu,ju)+aiu+1biu+1}+aibi}

  可以发现,状态f(i,j)总是通过f(iu,ju)转移得到,而iu(ju)=ij,即只要满足状态第一维减去第二维等于ij,那么就可以转移到f(i,j)。形象点理解的话,可以把n×k个状态看作是一个矩阵,f(i,j)表示矩阵中第i行第j列的元素,那么f(i,j)就可以从其所在的对角线之上的所有格子(状态)转移过来,如下图:

  例如状态f(7,4)就可以从f(6,3)f(5,2)f(4,2)转移过来。这有点类似于从某个前缀转移得到,不过在这里是斜线的前缀。一样的,我们可以用ij来代表某条斜线,然后分别维护每条斜线关于f(i,j)ai+1+bi+1f(i,j)+ai+1+bi+1f(i,j)ai+1bi+1f(i,j)+ai+1bi+1的前缀最大值,这样在状态转移时就可以降到O(1)

  AC代码如下,时间复杂度为O(nk)

复制代码
 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

posted @   onlyblues  阅读(46)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
历史上的今天:
2022-08-14 子数组异或和
Web Analytics
点击右上角即可分享
微信分享提示