洛谷 P4597 序列sequence 解題報告
阿新 • • 發佈:2018-11-07
數字 現在 clas %d 自己 1.7 報告 sca 理解
了
P4597 序列sequence
題目背景
原題\(\tt{cf13c}\)數據加強版
題目描述
給定一個序列,每次操作可以把某個數\(+1\)或\(-1\)。要求把序列變成非降數列。而且要求修改後的數列只能出現修改前的數。
輸入輸出格式
輸入格式:
第一行輸入一個\(n\),表示有\(n(n \leq 5\times10^5)\)個數字。
第二行輸入\(n\)個整數,整數的絕對值不超過\(10^9\)
輸出格式:
輸出一個數,表示最少的操作次數
發現之前洛谷做過一個類似的。。P2893
chen_zhe的題解並沒有看懂。
原題的\(N^2\)思路比較好想,離散化後直接開到狀態裏面就可以了。
然後維護一個按時間順序維護一個完整的非降數列,假設當前維護到位置\(i\)
當前數列的末尾為\(p\)
若\(p\le a_i\)
直接加入數列
若\(p>a_i\)
則把\(p\)和\(a_i\)作為一個二元組\((a_i,p)\)拿出來,那麽一定要花\(a_i-p\)的代價讓這個二元組變得不降
如果不考慮其他情況,那麽這個二元組可以取到的值為\((a_i,a_i),(a_i+1,a_i+1),\dots ,(p,p)\)
顯然取到最小值最好,那麽我們就當\(\tt{Ta}\)取到了最小值,然後把\(\tt{Ta}\)的最小值放到數列。雖然這時候可能比現在的末尾要小,不過沒關系,現在的新末尾也可能會改變。我們就當這個二元組在末尾大於\(\tt{Ta}\)
可以簡單的拿一個大根堆維護上述過程。
考慮為什麽這樣一定可以取到修改前的數,其實也很好理解,畢竟我們二元組取值要麽是自己,要麽就是某個末尾啊。
Code:
#include <cstdio> #include <queue> #define ll long long std::priority_queue <ll> q; ll ans=0,a;int n; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lld",&a); if(!q.empty()&&q.top()>a) { ans+=q.top()-a; q.pop(); q.push(a); } q.push(a); } printf("%lld\n",ans); return 0; }
2018.11.7
洛谷 P4597 序列sequence 解題報告