題目
n(n<=2^18)個人進行兩兩比賽,勝者晉級下一輪,敗者淘汰
第i個人的實力值是i,對任意一輪,你都可以指定還沒淘汰的人如何配對比賽,用他們的實力值比大小,
特別地,對於第i個人,你的朋友可以用ai(1<=ai<=1e9)的代價去賄賂他,使其直接被淘汰
你的朋友也出現在這個序列中,用-1標記,
這樣log輪後就只剩一人,求你的朋友最後成爲冠軍所花費的最小代價
思路來源
卿學姐的B站講解
題解
考慮以下圖形,不難發現,
①無論如何指派,1都會在第一輪被淘汰, 23在第二輪,以此類推,
通過合理安排,第k輪可以存活的最小能力值的人是2^k,所以第k輪過後前(2^k)-1個人一定被淘汰
因此,要儘量讓小的值和朋友在靠前的輪比賽,
這樣朋友碰到的對手就是越來越強的,也說明了能不賄賂就不賄賂
②朋友如果是4,則最多隻需要賄賂1輪,即賄賂8,
最後一輪只能賄賂8,倒數第二輪可以賄賂[5,8],其實是①得出的結論,以此類推
③比自己能力值小的人,顯然不用賄賂
基於以上三點,倒序考慮輪次,
當遇到2的冪次的時候,再被迫賄賂代價最小的
代碼
#include<bits/stdc++.h>
using namespace std;
const int N=(1<<18)+5;
typedef long long ll;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define sci(a) scanf("%d",&(a))
int n,a[N];
bool ok[N];
priority_queue<int,vector<int>,greater<int> >q;
ll ans;
int main(){
sci(n);
rep(i,1,n){
sci(a[i]);
}
rep(i,0,18){
ok[1<<i]=1;
}
per(i,n,1){
if(a[i]==-1)break;
q.push(a[i]);
if(ok[i]){
ans+=q.top();
q.pop();
}
}
printf("%lld\n",ans);
return 0;
}