D. Game With Triangles

D. Game With Triangles

There are $n+m$ distinct points $(a_1,0), (a_2,0), \ldots, (a_{n},0), (b_1,2), (b_2,2), \ldots, (b_{m},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 $k_{\max}$ be the maximum number of operations that can be performed. For example, if it is impossible to perform any operation, $k_\max$ 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 $0 \le k \le k_{\max}$.

Find the value of $k_{\max}$, and find the values of $f(x)$ for all integers $x=1,2,\ldots,k_{\max}$ independently.

Input

Each test contains multiple test cases. The first line contains the number of test cases $t$ ($1 \le t \le {3 \cdot 10^4}$). The description of the test cases follows.

The first line of each test case contains two integers $n$ and $m$ ($1 \le n,m \le 2 \cdot 10^5$).

The second line of each test case contains $n$ pairwise distinct integers $a_1,a_2,\ldots,a_{n}$ — the points on $y=0$ ($-10^9 \le a_i \le 10^9$).

The third line of each test case contains $m$ pairwise distinct integers $b_1,b_2,\ldots,b_{m}$ — the points on $y=2$ ($-10^9 \le b_i \le 10^9$).

It is guaranteed that both the sum of $n$ and the sum of $m$ over all test cases do not exceed $2 \cdot 10^5$.

Output

For each test case, given that the maximum number of operations is $k_{\max}$, you must output at most two lines:

  • The first line contains the value of $k_{\max}$;
  • The second line contains $k_{\max}$ integers denoting $f(1),f(2),\ldots,f(k_{\max})$. You are allowed to omit this line if $k_{\max}$ 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 $10^{16}$.

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 $k_{\max}$ 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 $k_{\max}$ 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 $(198\,872\,582,0)$, $(-1\,000\,000\,000,2)$, and $(1\,000\,000\,000,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\,000\,000\,000$. Therefore, the value of $f(1)$ is $2\,000\,000\,000$.

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

  • Choose three points $(-509\,489\,796,0)$, $(553\,177\,666,0)$, and $(-1\,000\,000\,000,2)$. The three points are erased.
  • Choose three points $(-400\,714\,529,0)$, $(564\,040\,265,0)$, and $(1\,000\,000\,000,2)$. The three points are erased.

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

 

解题思路

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

  先求解 $k_{\max}$。设 $x$ $\left(0 \leq x \leq  \min\left\{ n, \left\lfloor m/2 \right\rfloor \right\} \right)$ 为以点 $a$ 为顶点的三角形数量,那么以点 $b$ 为顶点的三角形数量最多为 $\min\left\{ \left\lfloor \frac{n-x}{2} \right\rfloor, m-2x  \right\}$。因此 $k_{\max} = \max\limits_{0 \leq x \leq  \min\left\{ n, \left\lfloor m/2 \right\rfloor \right\}}\left\{ x+\min\left\{ \left\lfloor \frac{n-x}{2} \right\rfloor, m-2x  \right\} \right\}$。

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

  假设选出 $k$ 个三角形的最大线段和为 $s_k$,为了快速得到 $k+1$ 个三角形的最大线段和,我们可以在 $s_k$ 的基础上得到 $s_{k+1}$,而无需重新求一遍。定义 $pa_i = a_{n-i+1} - a_i$,$pb_i = b_{m-i+1}-b_i$,$i$ 表示已从 $a$ 中选出的线段数量,$j$ 表示已从 $b$ 中选出的线段数量。$s_{k+1}$ 的结果有以下三种情况:

  1. 既可以从 $a$ 中选择线段,也可以从 $b$ 中选择线段。此时有 $n-(2i+j) \geq 2$ 和 $m-(2j+i) \geq 2$,我们只需根据 $pa_{i+1}$ 和 $pb_{j+1}$ 的大小,选择对应最长的线段即可,有 $s_{k+1} = s_k + max\{ pa_{i+1},pb_{j+1} \}$。
  2. 只能从 $a$ 中选择线段。如果 $m-(2j+i) = 1$,此时有 $n-(2i+j) \geq 2$,那么直接选择 $pa_{i+1}$ 即可,有 $s_{k+1} = s_k + pa_{i+1}$。如果 $m-(2j+i) = 0$,此时有 $n-(2i+j) \geq 3$,那么我们需要将线段 $pb_j$ 对应的三角形退化掉(因为 $k < k_{\max}$ 说明还能选,我们贪心地删去长度最短的线段),然后选择 $pa_{i+1}$ 和 $pa_{i+2}$,有 $s_{k+1} = s_k - pb_{j} + pa_{i+1}$ 和 $pa_{i+2}$。
  3. 只能从 $b$ 中选择线段。与上面分析类似,如果 $n-(2i+j) = 1$,此时有 $m-(2j+i) \geq 2$,那么直接选择 $pb_{j+1}$ 即可,有 $s_{k+1} = s_k + pb_{j+1}$。如果 $n-(2i+j) = 0$,此时有 $m-(2j+i) \geq 3$,那么我们需要将线段 $pa_i$ 对应的三角形退化掉,然后选择 $pb_{j+1}$ 和 $pb_{j+2}$,有 $s_{k+1} = s_k - pa_{i} + pb_{j+1}+ pb_{j+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(n\log{n})$:

#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$,对应的约束条件为

$$\begin{cases} 2x+y \leq n \\ 2y+x \leq m \\ x+y=k \\ 0 \leq x,y \leq k \end{cases}$$

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

  AC 代码如下,时间复杂度为 $O(n\log{n})$:

#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 @ 2025-01-27 23:19  onlyblues  阅读(100)  评论(0)    收藏  举报
Web Analytics