D. Doremy's Connecting Plan

发布时间 2023-10-29 19:41:39作者: onlyblues

D. Doremy's Connecting Plan

Doremy lives in a country consisting of $n$ cities numbered from $1$ to $n$, with $a_i$ people living in the $i$-th city. It can be modeled as an undirected graph with $n$ nodes.

Initially, there are no edges in the graph. Now Doremy wants to make the graph connected.

To do this, she can add an edge between $i$ and $j$ if

$$ \sum_{k \in S} a_k \ge i\cdot j \cdot c, $$

where $S$ is the set of all the nodes that are currently in the same connected component of either $i$ or $j$, and $c$ is a given constant.

Can Doremy make the graph connected?

Two nodes $(i, j)$ are in the same connected component if there exists a path from $i$ to $j$. A graph is connected if all its nodes are in the same connected component.

Input

The input consists of multiple test cases. The first line contains a single integer $t$ ($1\le t\le 10^4$) — the number of test cases. The description of the test cases follows.

The first line contains two integers $n$, $c$ ($2\le n\le 2\cdot 10^5$, $1 \le c \le 10^6$) — the number of nodes and the constant.

The second line of each test case contains $ n $ integers $ a_1,a_2,\ldots,a_n $ ($0 \le a_i \le 10^{12}$) — the number of people living in the $i$-th city.

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

Output

For each test case, print "YES" (without quotes), if it is possible to make the graph connected, and "NO" (without quotes) otherwise.

You can print letters in any case (upper or lower).

Example

input

7
4 10
0 20 15 10
2 1
1 1
5 1
0 1 0 4 199
5 2
1 1 3 1 1
5 5
5 6 1 10 2
5 1000000
1000000000000 1000000000000 1000000000000 1000000000000 1000000000000
3 1
0 0 2

output

Yes
Yes
Yes
No
No
Yes
No

Note

In the first test case, Doremy can add edges in the following order:

  1. Add $(1,2)$. This operation is valid because $a_1 + a_2 = 20 \ge i\cdot j \cdot c = 20$.
  2. Add $(1,3)$. This operation is valid because $a_1 + a_2 + a_3 = 35 \ge i \cdot j \cdot c = 30$.
  3. Add $(1,4)$. This operation is valid because $a_1 + a_2 + a_3 + a_4 = 45 \ge i \cdot j \cdot c = 40$.

In the second test case, Doremy can add edge $(1,2)$ because $a_1 + a_2 =2 \ge 1 \cdot 2 \cdot 1$. After that, the graph is connected.

In the third test case, Doremy can add edges in the order $(5,4)$, $(5,3)$, $(5,2)$ and $(5,1)$.

In the fourth test case, Doremy cannot add any edge at all.

 

解题思路

  昨晚这题卡了很久,好不容易做出来了结果因为乘法忘记转 long long 赛后被 hack 了,不然可以上大分。

  如果要把 $n$ 个节点变连通那么至少要加 $n-1$ 条边,意味着至少要进行 $n-1$ 次的连通块合并。定义节点 $i$ 所表示的连通块的总和为 $s_i = \sum{a_j}$,其中 $j$ 表示在该连通块中的节点。很显然为了让不等式尽可能成立,$i$ 应该是取连通块中最小节点标号。

  因此如果要合并两个连通块,那么就要满足 $s_i + s_j \geq i \cdot j \cdot c$。如果确实存在这样的 $i$ 和 $j$($i$ 与 $j$ 均不为 $1$),昨晚就猜能否把其中一个换成 $1$ 所在的连通块呢?如果可以的话那么以下两个不等式必然至少有一个成立:$$\begin{cases} s_1 + s_i \geq i \cdot c \\ s_1 + s_j \geq j \cdot c \end{cases}$$

  反证法,如果存在 $i \geq 2$ 和 $j \geq 2$ 且 $i \ne j$ 满足 $s_i + s_j \geq i \cdot j \cdot c$,并且有 $\displaylines{\begin{cases} s_1 + s_i < i \cdot c \\ s_1 + s_j < j \cdot c \end{cases}}$,那么我们就可以推出

\begin{align*}
s_i + s_j &< (i+j) \cdot c - 2s_1 \\
&< (i+j) \cdot c \\
&< i \cdot j \cdot c
\end{align*}

  这就与 $s_i + s_j \geq i \cdot j \cdot c$ 矛盾了。

补充一下 $i \cdot j \geq i + j \; (i \geq 2, \, j \geq 2)$ 的证明。

$i \cdot j \geq i + j \; \Rightarrow \; i \cdot j - i - j \geq 0$,而 $i \cdot j - i - j = (i-1)(j-1)-1 \geq (2-1)(2-1)-1 = 0$,得证。

当 $i = j = 2$ 时取等号。

  意味着我们每次只需选一个节点合并到 $1$ 号节点所在的连通块即可,那么可选的节点 $i$ 就要满足 $a_i + s_1 \geq i \cdot c$,即 $i \cdot c - a_i \leq s_1$。为此为了可以合并尽可能多的节点,我们从 $i \cdot c - a_i$ 最小的节点开始合并。所以可以对 $2 \sim n$ 的节点按照 $i \cdot c - a_i$ 进行排序,从小到大枚举如果发现 $i \cdot c - a_i$ 那就将 $i$ 合并到 $1$ 号节点所在连通块,有 $s_1 \gets s_1 + a_i $,否则无法合并,输出无解。

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

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

typedef long long LL;

const int N = 2e5 + 10;

LL a[N];
int p[N];

void solve() {
    int n, m;
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%lld", a + i);
        p[i] = i;
    }
    sort(p + 2, p + n + 1, [&](int i, int j) {
        return 1ll * i * m - a[i] < 1ll * j * m - a[j];
    });
    LL s = a[1];
    for (int i = 2; i <= n; i++) {
        s += a[p[i]];
        if (s < 1ll * p[i] * m) {
            printf("NO\n");
            return;
        }
    }
    printf("YES\n");
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        solve();
    }
    
    return 0;
}

 

参考资料

  Codeforces Round 906 Editorial:https://codeforces.com/blog/entry/121813