啟智樹提高組Day3 T3 pancake
阿新 • • 發佈:2020-08-26
現有 \(n\) 個線段,第 \(i\) 個線段長度為 \(l_i\),現最多可以切 \(k\) 刀,只能在整數位置切。要求最小化切完後所有線段的長度的平方和。又有 \(q\) 次操作,每次將 \(k\) 加一或減一,或者新加一段長為 \(l_i\) 的線段。每次問最小的平方和。\(n,q,l_i,k \le 10^5\)。保證答案不爆 long long
首先 \(nqk\) 的揹包DP就不說了,反正正解和這沒啥關係。
注意不到平方和關於切的刀數是個下凸函式,或者說平方和的減少量這個東西關於切的刀數 \(k\) 是個減函式。於是可以費用流。
考慮一種網路流模型,將代價轉化為 $l_i^2 - $ 切 \(k\)
考慮模擬費用流。用一個堆維護每個段當前能擴展出來的差分,再用一個堆來維護已經選擇的那些差分。先撿收益大的 \(k\) 個差分作為初始答案。如果 \(k\) 加一,那麼從第一個堆中找出最大的那個扔到第二個堆中並計入答案;如果 \(k\) 減一,那麼從第二個堆中選出最小的那個,放棄掉它。
對於新加入一個段,我們可以直接暴力做,一直到它能擴展出來的差分小於已經選擇的最小的差分。我目前不會證複雜度(據說總共 \(O(nlogn)\)
總複雜度\(O(nlog^2n)\)。
關鍵程式碼:
struct node { int cur; ll val; bool operator <(const node a) const { return val < a.val || (val == a.val && cur < a.cur); } }; inline ll calc(int x, int k) { int rst = x % k; int xia = x / k; int shang = (x + k - 1) / k; ll res= 1ll * xia * xia * (k - rst) + 1ll * shang * shang * rst; return res; } inline ll Calc(int x, int k) { ll res = calc(h[x], k) - calc(h[x], k + 1); return res; } multiset<node> st, ts; inline void init() { for (register int i = 1; i <= n; ++i) ts.insert((node){i, Calc(i, cnt[i])}); for (register int i = 1; i <= k; ++i) { node nd = *(--ts.end()); ts.erase(nd); st.insert(nd); res += nd.val; ts.insert((node){nd.cur, Calc(nd.cur, ++cnt[nd.cur])}); } } inline void add() { ++k; node nd = *(--ts.end()); ts.erase(nd); st.insert(nd); res += nd.val; ts.insert((node){nd.cur, Calc(nd.cur, ++cnt[nd.cur])}); } inline void del() { --k; node nd = *(st.begin()); res -= nd.val; st.erase(st.begin()); ts.erase((node){nd.cur, Calc(nd.cur, cnt[nd.cur])}); --cnt[nd.cur]; ts.insert((node){nd.cur, Calc(nd.cur, cnt[nd.cur])}); } inline void ins(int i) { ts.insert((node){i, Calc(i, cnt[i])}); while ((*(--ts.end())).val > (*st.begin()).val) { node nd = (*st.begin()); st.erase(st.begin()); st.insert(*(--ts.end())), ts.erase(--ts.end()), res += Calc(i, cnt[i]), ts.insert((node){i, Calc(i, ++cnt[i])}); res -= nd.val; ts.erase(ts.find((node){nd.cur, Calc(nd.cur, cnt[nd.cur])})); --cnt[nd.cur]; ts.insert((node){nd.cur, Calc(nd.cur, cnt[nd.cur])}); } }