Educational Codeforces Round 77 (Rated for Div. 2) E. Tournament(思维题)

题目

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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章