D. Game With Triangles

D. Game With Triangles

There are n+m distinct points (a1,0),(a2,0),,(an,0),(b1,2),(b2,2),,(bm,2) on the plane. Initially, your score is 0. To increase your score, you can perform the following operation:

  • Choose three distinct points which are not collinear;
  • Increase your score by the area of the triangle formed by these three points;
  • Then, erase the three points from the plane.

An instance of the game, where the operation is performed twice.

Let kmax be the maximum number of operations that can be performed. For example, if it is impossible to perform any operation, kmax is 0. Additionally, define f(k) as the maximum possible score achievable by performing the operation exactly k times. Here, f(k) is defined for all integers k such that 0kkmax.

Find the value of kmax, and find the values of f(x) for all integers x=1,2,,kmax independently.

Input

Each test contains multiple test cases. The first line contains the number of test cases t (1t3104). The description of the test cases follows.

The first line of each test case contains two integers n and m (1n,m2105).

The second line of each test case contains n pairwise distinct integers a1,a2,,an — the points on y=0 (109ai109).

The third line of each test case contains m pairwise distinct integers b1,b2,,bm — the points on y=2 (109bi109).

It is guaranteed that both the sum of n and the sum of m over all test cases do not exceed 2105.

Output

For each test case, given that the maximum number of operations is kmax, you must output at most two lines:

  • The first line contains the value of kmax;
  • The second line contains kmax integers denoting f(1),f(2),,f(kmax). You are allowed to omit this line if kmax is 0.

Note that under the constraints of this problem, it can be shown that all values of f(x) are integers no greater than 1016.

Example

Input

5
1 3
0
0 1 -1
2 4
0 100
-100 -50 0 50
2 4
0 1000
-100 -50 0 50
6 6
20 1 27 100 43 42
100 84 1 24 22 77
8 2
564040265 -509489796 469913620 198872582 -400714529 553177666 131159391 -20796763
-1000000000 1000000000

Output

1
2
2
150 200
2
1000 200
4
99 198 260 283
2
2000000000 2027422256

Note

On the first test case, there are 1+3=4 points (0,0),(0,2),(1,2),(1,2).

It can be shown that you cannot perform two or more operations. The value of kmax is 1, and you are only asked for the value of f(1).

You can choose (0,0), (1,2), and (1,2) as the three vertices of the triangle. After that, your score is increased by the area of the triangle, which is 2. Then, the three points are erased from the plane. It can be shown that the maximum value of your score after performing one operation is 2. Therefore, the value of f(1) is 2.

On the fifth test case, there are 8+2=10 points.

It can be shown that you cannot perform three or more operations. The value of kmax is 2, and you are asked for the values f(1) and f(2).

To maximize the score with only one operation, you can choose three points (198872582,0), (1000000000,2), and (1000000000,2). Then, the three points are erased from the plane. It can be shown that the maximum value of your score after performing one operation is 2000000000. Therefore, the value of f(1) is 2000000000.

To maximize the score with exactly two operations, you can choose the following sequence of operations.

  • Choose three points (509489796,0), (553177666,0), and (1000000000,2). The three points are erased.
  • Choose three points (400714529,0), (564040265,0), and (1000000000,2). The three points are erased.

Then, the score after two operations becomes 2027422256. It can be shown that the maximum value of your score after performing exactly two operations is 2027422256. Therefore, the value of f(2) is 2027422256.

 

解题思路

  把在 y=0 上的点称为点 a,在 y=2 上的点称为点 b。三角形分为两种,底边要么是两个点 a 构成的线段,要么是两个点 b 构成的线段。由于三角形的高都是 2,因此面积就是底边的长度,也即两点构成线段的长度。因此问题转换成了选出的线段总长度最大。

  先求解 kmax。设 x (0xmin{n,m/2}) 为以点 a 为顶点的三角形数量,那么以点 b 为顶点的三角形数量最多为 min{nx2,m2x}。因此 kmax=max0xmin{n,m/2}{x+min{nx2,m2x}}

  考虑如何选择线段。当我们需要从点 a 中选出 k 条线段,为了使得总长度最大,一种贪心的选法是让首尾的点构成线段,此时总长度为 i=1kakank+1。从直观上理解,这种选法使线段尽可能覆盖多的位置,从而长度最长。

  假设选出 k 个三角形的最大线段和为 sk,为了快速得到 k+1 个三角形的最大线段和,我们可以在 sk 的基础上得到 sk+1,而无需重新求一遍。定义 pai=ani+1aipbi=bmi+1bii 表示已从 a 中选出的线段数量,j 表示已从 b 中选出的线段数量。sk+1 的结果有以下三种情况:

  1. 既可以从 a 中选择线段,也可以从 b 中选择线段。此时有 n(2i+j)2m(2j+i)2,我们只需根据 pai+1pbj+1 的大小,选择对应最长的线段即可,有 sk+1=sk+max{pai+1,pbj+1}
  2. 只能从 a 中选择线段。如果 m(2j+i)=1,此时有 n(2i+j)2,那么直接选择 pai+1 即可,有 sk+1=sk+pai+1。如果 m(2j+i)=0,此时有 n(2i+j)3,那么我们需要将线段 pbj 对应的三角形退化掉(因为 k<kmax 说明还能选,我们贪心地删去长度最短的线段),然后选择 pai+1pai+2,有 sk+1=skpbj+pai+1pai+2
  3. 只能从 b 中选择线段。与上面分析类似,如果 n(2i+j)=1,此时有 m(2j+i)2,那么直接选择 pbj+1 即可,有 sk+1=sk+pbj+1。如果 n(2i+j)=0,此时有 m(2j+i)3,那么我们需要将线段 pai 对应的三角形退化掉,然后选择 pbj+1pbj+2,有 sk+1=skpai+pbj+1+pbj+2

  将三种情况综合得到的相应代码如下(下标从 0 开始):

if (2 * i + j == n) s += pb[j++] - pa[--i];
else if (2 * j + i == m) s += pa[i++] - pb[--j];
if (n - 2 * i - j >= 2 && (m - 2 * j - i < 2 || pa[i] > pb[j])) s += pa[i++];
else s += pb[j++];

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

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 2e5 + 5;

int a[N], b[N], pa[N], pb[N];

void solve() {
    int n, m;
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    for (int i = 0; i < m; i++) {
        cin >> b[i];
    }
    sort(a, a + n);
    sort(b, b + m);
    for (int i = 0, j = n - 1; i < j; i++, j--) {
        pa[i] = a[j] - a[i];
    }
    for (int i = 0, j = m - 1; i < j; i++, j--) {
        pb[i] = b[j] - b[i];
    }
    int k = 0;
    for (int i = 0; i <= n && i <= m >> 1; i++) {
        k = max(k, i + min(n - i >> 1, m - 2 * i));
    }
    cout << k << '\n';
    LL i = 0, j = 0, s = 0;
    while (k--) {
        if (2 * i + j == n) s += pb[j++] - pa[--i];
        else if (2 * j + i == m) s += pa[i++] - pb[--j];
        if (n - 2 * i - j >= 2 && (m - 2 * j - i < 2 || pa[i] > pb[j])) s += pa[i++];
        else s += pb[j++];
        cout << s << ' ';
    }
    cout << '\n';
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    
    return 0;
}

  再介绍一下官方题解的做法。分析和上面的基本一样,不同的地方在于每一个 k 通过三分来独立求解。但我感觉三分的做法并不直观,不太容易往凸函数的方面想。

  当要选出 k 个三角形时,假设从 a 中选出的线段为 x,从 b 中选出的线段为 y,对应的约束条件为

{2x+yn2y+xmx+y=k0x,yk

  可以解得 max{0,2km}xmin{k,nk}。然后在这个范围内三分 x,使得式子 i=1xpai+i=1kxpbi 的结果最大。该式是一个关于 x 的凸函数(实际上应该是凹函数,但这里只关注是否具有凹凸性),这是因为 i=1xpaii=1kxpbi 都是单调的函数,意味着也是凸函数,而两个凸函数的和也是凸函数。代码实现中是用二分斜率来代替三分。

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

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 2e5 + 5;

int a[N], b[N];
LL sa[N], sb[N];

void solve() {
    int n, m;
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    for (int i = 0; i < m; i++) {
        cin >> b[i];
    }
    sort(a, a + n);
    sort(b, b + m);
    for (int i = 0, j = n - 1; i < j; i++, j--) {
        sa[i + 1] = sa[i] + a[j] - a[i];
    }
    for (int i = 0, j = m - 1; i < j; i++, j--) {
        sb[i + 1] = sb[i] + b[j] - b[i];
    }
    int k = 0;
    for (int i = 0; i <= n && i <= m >> 1; i++) {
        k = max(k, i + min(n - i >> 1, m - 2 * i));
    }
    cout << k << '\n';
    for (int i = 1; i <= k; i++) {
        int l = max(0, 2 * i - m), r = min(i, n - i), t = l;
        auto get = [&](int x) {
            if (x < t) return -1ll;
            return sa[x] + sb[i - x];
        };
        while (l < r) {
            int mid = l + r + 1 >> 1;
            if (get(mid) - get(mid - 1) >= 0) l = mid;
            else r = mid - 1;
        }
        cout << get(l) << ' ';
    }
    cout << '\n';
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    
    return 0;
}

 

参考资料

  CF2063:https://www.cnblogs.com/denghaoxuan/articles/18689043

  Codeforces Round 1000 (Div. 2) — Editorial:https://codeforces.com/blog/entry/138593

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