還記得 NOIP 2012 提升組 Day1 的國王遊戲嗎?時光飛逝,光陰荏苒,兩年html
過去了。國王遊戲早已過期,現在已被皇后遊戲取代,請你來解決相似於國王遊node
戲的另外一個問題。c++
皇后有 n 位大臣,每位大臣的左右手上面分別寫上了一個正整數。恰逢國慶算法
節來臨,皇后決定爲 n 位大臣頒發獎金,其中第 i 位大臣所得到的獎金數目爲第數組
i-1 位大臣所得到獎金數目與前 i 位大臣左手上的數的和的較大值再加上第 i 位學習
大臣右手上的數。spa
形式化地講:咱們設第 i 位大臣左手上的正整數爲 ai,右手上的正整數爲 bi,code
則第 i 位大臣得到的獎金數目爲 ci能夠表達爲:htm
固然,吝嗇的皇后並不但願太多的獎金被髮給大臣,因此她想請你來從新安blog
排一下隊伍的順序,使得得到獎金最多的大臣,所獲獎金數目儘量的少。
注意:從新安排隊伍並不意味着必定要打亂順序,咱們容許不改變任何一
位大臣的位置。
n<=20000,保證不會爆long long
參考/推薦:題解 P2123 【皇后遊戲】
確實是一道值得深刻思考的好問題!!!
背景既然提示了和國王遊戲有關係,而且顯然也是一個排序的貪心題目。
也必定是用微擾法(交換臨項法)尋找並證實。
(由於交換相鄰兩項不會影響別的項)
不妨設,前面的一我的是i,後面一我的是i+1
i前面的一我的的c值爲p,i前面的人的a總和是sum
那麼,咱們如今要找到i在i+1前面的條件。
①i在i+1前面:
貢獻:
$max(max(p,sum+a_i)+b_i,sum+a_i+a_{i+1})+b_{i+1}$
化簡一下就是:
$max(p+b_i+b_{i+1},sum+a_i+b_i+b_{i+1},sum+a_i+a_{i+1}+b_{i+1})$
②同理,i+1在i前面
化簡之後是:
$max(p+b_i+b_{i+1},sum+a_{i+1}+b_i+b_{i+1},sum+a_i+a_{i+1}+b_i)$
咱們如今要探究①小於②的條件
發現,共同有的是:$p+b_i+b_{i+1}$
這一項能夠兩邊直接消掉。最終不會影響排序的結果。
那麼就是比較:
$max(sum+a_i+b_i+b_{i+1},sum+a_i+a_{i+1}+b_{i+1})$
和
$max(sum+a_{i+1}+b_i+b_{i+1},sum+a_i+a_{i+1}+b_i)$
去掉sum,再化簡一下:
$max(b_i,a_{i+1})+a_i+b_{i+1}<=max(b_{i+1},a_i)+a_{i+1}+b_i$
移項,
$max(b_i,a_{i+1})-a_{i+1}-b_i<=max(b_{i+1},a_i)-a_i-b_{i+1}$
其實這個式子的含義是:
兩邊的較大值會被減掉,較小值的相反數會留下來
因此,實際上是:
$-min(a_{i+1},b_i)<=-min(a_i,b_{i+1})$
也就是:
$min(a_i,b_{i+1})<=min(a_{i+1},b_i)$
看似是一個很簡單的公式!!
那麼直接排序?
luogu反正是AC了。
可是其實不對!
咱們發現,這個式子不具備傳遞性,
也就是說,
這種重載小於號的方式,並不知足
$a<=b,b<=c \space\ \to \space\ a<=c$
手動出幾組就能夠hack掉。
而咱們的sort本質是快速排序實現的。
咱們分治的每層子區間會選擇一個隨機的x做爲基準,把小於x放在x左邊,大於x放在x右邊,
這個排序的正確性,顯然要有<知足傳遞性的性質才行。
因此,這個式子用sort排出來,根據原始輸入順序、基準的x選取的不一樣,排出來的順序也是不一樣的,答案也就是不一樣的了。
那麼怎麼辦?
繼續觀察這個式子:
$min(a_i,b_{i+1})<=min(a_{i+1},b_i)$
能夠(也許很難)想到,和ai,bi自己有關係?
顯然,若是排序的式子和ai,bi自己放在一塊兒,是必定有傳遞性的。
(例如:
$min(a_1,b_1)<=min(a_2,b_2),min(a_2,b_2)<=min(a_3,b_3) \space\ \to \space\ min(a_1,b_1)<=min(a_3,b_3)$
)
咱們只好討論了。
1.$a_i<b_i,a_{i+1}<b_{i+1}$
那麼就是:$a_i<=a_{i+1}$
因此這一塊按照a升序排序。
2.$a_i=b_i,a{i+1}=b_{i+1}$
隨便排便可。
3.$a_i>b_i,a_{i+1}>b_{i+1}$
那麼就是:$b_{i+1}<=b_i$
因此這一塊按照b降序排序
那麼,如今全部的序列會被分紅這三大塊。
塊與塊之間怎麼辦?
1應該在2前面。2應該在3前面。
即1前,2中,3後。
證實:
1在2前面,2在3前面顯然能夠證實。
設一、3中的一個元素分別是$(a_1,b_1),(a_3,b_3)$
由於有$a_1<b_1,a_3>b_3$
因此,必定有$min(a_1,b_3)<=min(a_3,b_1)$
每一個組內部有傳遞性,組與組之間也有傳遞性。
因此這種排序就具備傳遞性。
這樣就能夠了。
爲了方便,能夠定義一我的的組別d爲:
$\frac{a_i-b_i}{|a_i-b_i|}$
1組對應-1,2組對應0,三組對應1
因此,咱們的排序能夠這樣進行
先按照d爲第一關鍵字,分到每一個組裏。
d相同,按照組內的排序方式。
(對了還有一個鍋,重載的小於號不能帶=,必須小於號才行。
由於快排的內部實現可能會出問題。
$while(a[i]<=a[x]) i++ $
i=x不會中止,假設x是最後一個,就可能數組越界!! RE)
代碼:
#include<bits/stdc++.h>
using namespace std; typedef long long ll; const int N=20000+5; int t,n; struct node{ int a,b; int d; bool friend operator <(node x,node y){ if(x.d!=y.d) return x.d<y.d; if(x.d<=0) return x.a<y.a; else return x.b>y.b; } }a[N]; ll c[N]; int main(){ scanf("%d",&t); while(t--){ ll ans=0; memset(c,0,sizeof c); scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d%d",&a[i].a,&a[i].b),a[i].d=(a[i].a-a[i].b)/abs(a[i].a-a[i].b); sort(a+1,a+n+1); ll sum=0; for(int i=1;i<=n;i++){ sum+=a[i].a; c[i]=max(c[i-1],sum)+a[i].b; ans=max(ans,c[i]); } printf("%lld\n",ans); } return 0; } /* Author: *Miracle* Date: 2018/9/23 22:50:00 */
總結:
很是很是很是很是....漂亮的一道題,不是算法的混雜,就是一個單單對排序的理解和處理。
大體的思路是:
1.微擾法思想,列式子。
2.化簡式子。到了兩個min的式子。
3.發現,不知足排序的傳遞性。
4.儘可能向ai,bi自己的屬性靠近,而不是加上相鄰的項,把這個條件做爲斷定的條件(鄰居畢竟不靠譜,多是誰都不知道)
5.列出最終的式子。
6.證實了傳遞性的存在。
(根據快排的原理,而後注意重載小於號不能加=)
啓示咱們學習算法要學到算法的應用條件和原理本質上,
比如排序的<的定義要有傳遞性,快排不能<=會RE,微擾法本質的使用條件是,交換這兩項,對前面後面的值都無影響。
而不是隻知其一;不知其二,囫圇吞棗,死記硬背,直接複製。
值得思考。
完結撒花~~~