[NOI2015] 荷马史诗 题解

/*
思路,
	简化题意, 即构造一颗 k 叉树, 每个节点的
	权值为其所有孩子的权值之和, 给定的 n 个
	数必须使用, 其余空缺处用 0 补全. 

	考虑使用优先队列, 首先弹入 n + (n-1) % 
	(k-1) 个元素 ( 不足处用 0 代替), 然后每
	次弹出前 k 小的数并插入其和, 知道优先队
	列中只剩余一个元素. 计算时同时保存深度.
	
	由于优先队列默认从大到小排序, 而用 pair
	比较方便, 所以处理时我们将队列中的数取
	反, 计算结果时再次取相反数. 
*/
#include <stdio.h>
#include <iostream>
#include <queue>
#define ll long long
using namespace std;

ll n, k;
priority_queue < pair <ll, ll> > pq;
int main () {
	scanf("%lld %lld", &n, &k);
	for (int i = 1; i <= n; i++) {
		ll x;
		scanf("%lld", &x);
		pq.push(make_pair(-x, 0));
	}
	
	// 插入 0: 
	while ((n - 1) % (k - 1)) {
		pq.push(make_pair(0, 0));
		n++;
	}
	
	ll ans = 0;
	while (pq.size() != 1) {
		ll sigma = 0, high = 0;
		for (int i = 1; i <= k; i++) {
			sigma += pq.top().first;
			high = min(high, pq.top().second);
			pq.pop();
		}
		pq.push(make_pair(sigma, high - 1)); // 注意 high 也是一个非正数
		ans += sigma; 
	} 
	printf("%lld\n%lld\n", -ans, -pq.top().second);
	return 0;
}
posted @ 2021-07-19 23:45  dbg_8  阅读(178)  评论(0)    收藏  举报