codeforces 608 div2 portals(带反悔的贪心)

题目大意:我们要攻略n个城堡,每个城堡有ai,bi,ci三个参数,我们到达城堡i时必须至少有ai个人才能攻略,不能攻略输出-1

到达一个城堡后能够加bi个人。同时我们允许放1个人在城堡i防守,这样我们能得到ci的分数。注意过了这个城堡就不能再选择之前的城堡进行防守。但是,这里有一些道路允许我们在城堡b到城堡a,其中b大于a。

解题思路:

很自然地,我们每次到达一个城堡都尽可能进行defend,每次到达一个城堡若人数不够,我们就反悔,把之前分数低的defend的城市取消。大概思路就是这样,我们只用维护一个优先队列就可以了。但是上面的思路有些问题,我们在人数不够的时候,优先pop出来的是分数低的,这样有个bug,比如可能到达某座城市i,它可能和一些城市连起来,这时候我们应该pop掉和i连接的城市。那怎么避免这种情况呢?这里有一个key hint。 一个城市若是后面可以defend,我们不要在前面就defend,这样总是最优的,比如i和j是连起来的,其中j>i,这时候我们假如不在i defend在jdefend的好处是:[i+1,j]区间人数多了一个,更有利于我们攻略城堡。而且这样可以避免我们之前所说的bug。

#include <bits/stdc++.h>
using namespace std;
typedef struct{
    int a,b,c;
}cas;
vector<vector<int>> gra;
vector<int> flag;
vector<int>  back;
int main(){
    int n,m,k;cin>>n>>m>>k;
    vector<cas> castle(n);
    back.assign(n,0);
    flag=vector<int> (n,0);
    for(int i=0;i<n;i++){
        cin>>castle[i].a>>castle[i].b>>castle[i].c;
    }
    gra=vector<vector<int>> (n);
    for(int i=0;i<m;i++){
        int a,b;cin>>a>>b;
        a-=1;b-=1;
        gra[a].emplace_back(b);
        back[b]=max(back[b],a);
    }
    priority_queue<pair<int,int>,vector<pair<int,int>> ,greater<pair<int,int>>> pq;
    int man=k;
    for(int i=0;i<n;i++){
        if(man<castle[i].a){
           int dif=castle[i].a-man;
           if((int)pq.size()<dif){
               cout<<-1<<endl;
               exit(0);
           }else{
               while(man<castle[i].a){
                   pair<int,int> ii= pq.top();
                   flag[ii.second]=0;
                   pq.pop();
                   man++;
                }
            }
        }
        man+=castle[i].b;
        if(man){
            priority_queue<pair<int,int> ,vector<pair<int,int>> , less<pair<int,int>> > tmp;
            if(!back[i])
            tmp.push(make_pair(castle[i].c,i));
            for(int ii=0;ii<(int)gra[i].size();ii++){
                 int nx=gra[i][ii];
                 if(back[nx]!=i)continue;
                if(!flag[nx]){
                    tmp.push(make_pair(castle[nx].c,nx));
                }
            }
            while(tmp.size()>0 && man>0){
                pair<int,int> ii=tmp.top();
                tmp.pop();
                flag[ii.second]=1;
                pq.push(make_pair(ii.first,ii.second));
                man-=1;
            }
        }
    }
    int ans=0;
    while(pq.size()){
        int no=pq.top().first;
        pq.pop();
        ans+=no;
    }
    cout<<ans<<endl;
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值