1890D - Doremy's Connecting Plan
题意:给定两个数字 n 、c和一个长度为n的数组 ,现有n个孤立点,第 i 个孤立点的权值为
,现需要通过建边将所有点全部连通。在第 i 个点和第 j 个点建边需要满足条件:
(S为 i 所在连通块的点和 j 所在连通块的点的集合)。判断能否建成连通图。
思路 : 观察式子右边,发现 i * j 越小容易建边,因此考虑能否和第1个点进行建边。当无法和第一个点建边时,则表示 , 放缩可得
, 那么考虑跟其他点建立边时必然有
。因此当无法和点1建边时,必然无法和其他点建边。由此可得:我们只需要每次都和第一个点所在连通块建边即可。那么建边条件弱化为:
(其中s为第一个点所在连通块的集合)。转移后得到:
。 于是右边的式子我们就可以进行预处理了,然后对右边的值贪心一波即可。
// Problem: D. Doremy's Connecting Plan
// Contest: Codeforces - Codeforces Round 906 (Div. 2)
// URL: https://codeforces.com/contest/1890/problem/D
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
const LL maxn = 4e05+7;
const LL N=2e05+10;
const LL mod=1e09+7;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >t;
priority_queue<LL> q;
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
struct Node{
LL num = 0;
LL res = 0;
};
int cmp(Node a , Node b){
return a.res > b.res;
}
void solve()
{
LL n , c;
cin>>n>>c;
Node a[n + 5];
int vis[n + 5];
memset(vis , 0 , sizeof vis);
for(int i = 1; i <= n ; i++){
cin>>a[i].num;
}
for(int i = 2 ; i <= n ; i ++){
a[i].res = a[i].num - i * c;
}
sort(a + 2 , a + n + 1 , cmp);
for(int i = 2 ; i <= n ; i ++){
if(a[1].num + a[i].res >= 0){
a[1].num += a[i].num;
}
else{
cout<<"NO\n";
return;
}
}
cout<<"YES\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}