n个结点,第i个结点的权值为a[i],给定c,如果a[i] + a[j] >= i * j * c, 那么i和j直接可以连一条边,并且i、j缩成一个点,权值为两点权值之和, 编号为min(i, j)

题目

思路:

先考虑在哪两个结点连边:先用结点1和其他结点连边一定是最优解之一,假设有三个结点,2,3可以连边,那么有a[2] + a[3] >= 2 * 3 * c(那么a[2], a[3]至少有一个大于等于3c), 1不能和2、3连,有a[1] + a[2] < 2 * c, a[1] + a[3] < 3 * c,与前面矛盾。

综上,让所有结点按 a[1] + a[i] - i * c排序,依次跟结点1合并

#include
using namespace std;
#define int long long
const int maxn = 1e6 + 5;
int a[maxn];
int n, c;
struct Node{
	int num, id;
	bool operator < (const Node &u) const{
		return num - id * c > u.num - u.id * c;
	}
}b[maxn];
void solve(){
	cin >> n >> c;
	for(int i = 1; i <= n; i++){
		cin >> a[i];
		b[i] = {a[i], i};
	}
	sort(b + 2, b + n + 1);
	int now = a[1];
	for(int i = 2; i <= n; i++){
		int num = b[i].num, id = b[i].id;
		if(now + num < id * c){
			cout << "No\n";
			return;
		}
		now += num;
	}
	cout << "Yes\n";
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	int T;
	cin >> T;
	while(T--){
		solve();
	}
	return 0;
}

你可能感兴趣的:(codeforces,c语言,算法,开发语言)