【NOI2015】荷马史诗
顯然一個Huffman樹,然后改成 \(K\) 叉的就好。但是我不會Huffman樹,于是學學拓寬知識面。
首先這個 \(K\) 叉樹就是一個類似字典樹的東西,但是不對應目標串的點都是非葉結點(不然不滿足前綴關系的限制)
容易證明,每個點帶 \(K - 1\) 個葉子是最優的。
考慮計算總權值時的 深度乘以權值 改為 它到根的鏈上都加上它的權值,那么 \(\sum dep_i \times val_i = \sum_{u \notin leaves} v_i\)。
于是讓權值大的盡量貢獻最少,那么就要出現在深度淺的地方。
因此考慮自底向上構建。考慮維護一個堆,每次取出前 \(K\) 小的,合并成一個點,然后扔進堆里。合并的時候維護權值(子節點的和)。直到合并成單個點。顯然,權值越大的貢獻次數越小。于是這樣貪心是正確的(然而我并不會嚴格的證明)。
然后就建出一個 Huffman樹了。但是對于第二問我們還是要得出深度最小值,于是加入第二關鍵字深度,合并的時候注意維護就行了。
還有因為每次減少 \(K - 1\) 個,所以可能最后剩下不是 \(1\) 個,所以,補上幾個 \(0\) 使得 \(n \equiv 1\ (\mod K - 1)\),顯然不會對答案產生影響。
我掛在了補 \(0\) 以及 第二關鍵字上,WA了兩發。
#include <bits/stdc++.h>typedef long long LL; typedef std::pair<LL, int> P; std::priority_queue<P, std::vector<P>, std::greater<P> > q; int n, K; LL t; int main() {std::ios_base::sync_with_stdio(false), std::cin.tie(0);std::cin >> n >> K;for (int i = 1; i <= n; ++i) std::cin >> t, q.emplace(t, 0);while (n % (K - 1) != 1 % (K - 1)) ++n, q.emplace(0, 0);LL ans = 0;while (q.size() != 1) {LL tv = 0; int dx = 0;for (int i = 1; i <= K; ++i)tv += q.top().first, dx = std::max(dx, q.top().second), q.pop();q.emplace(tv, dx + 1); ans += tv;}std::cout << ans << std::endl << q.top().second << std::endl;return 0; }轉載于:https://www.cnblogs.com/daklqw/p/11587281.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的【NOI2015】荷马史诗的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 黑马lavarel教程---9、缓存操作
- 下一篇: 【集训队作业2018】复读机