Jzoj P1142.剑与魔法___优先队列

13 篇文章 0 订阅

题目大意:

事件分为两类:战役事件 CASE C A S E 和穿越回去事件 END E N D
战役事件可以选择是否参加,参加后会获得一定金钱。
END事件发生需要至少参加一定数量的战役事件。
特别的是,END事件如果满足要求就会强制发生。
要求只有最后一个END事件会发生。
问此时获得最多的金钱数,无法满足则输出 1 − 1

N<=200,000 N <= 200 , 000
每次赏金不超过 10,000 10 , 000
穿越事件的要求不超过 200,000 200 , 000

分析:

END E N D 事件的要求限制成一个满足要求的递增序列,
即除了最后一个,其他的都满足前面 <= <= <script type="math/tex" id="MathJax-Element-122"><=</script>后面,
然后维护一个满足要求的小根堆即可。
最后判断堆中元素个数,如果没有>=最后一个END的要求则无解,否则计算堆中元素总和即为答案。

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define N 200005

using namespace std;

struct Node {
    int x, id;
    friend bool operator < (Node aa, Node bb) 
    {
        return aa.x > bb.x;
    }
}a[N];
struct Code { int x, id; }b[N];
priority_queue <Node> Q;
char str[10];
int ans, last, cnt, tot, n;

int main()
{
    freopen("data.in","r",stdin);
    scanf("%d", &n);
    last = 0; 
    for (int i = 1; i <= n; i++)
    {
         scanf("%s", str);
         if (str[0] == 'c') 
         {
             scanf("%d", &a[++cnt].x);
             a[cnt].id = i;
         }
         else 
         {
             scanf("%d", &b[++tot].x);
             b[tot].id = i;
         } 
    }
    int now = b[tot - 1].x;
    for (int i = tot - 2; i >= 1; i--)
         if (b[i].x > now) b[i].x = now;
                      else now = min(now, b[i].x);
    int l1 = 1, l2 = 1;
    while (l1 <= cnt && l2 <= tot - 1)
    {
           while (l1 <= cnt && a[l1].id <= b[l2].id) 
           {
                  if (Q.size() < b[l2].x - 1) Q.push(a[l1]);
                  else 
                  {
                      if (Q.size() != 0)
                          if (a[l1].x > Q.top().x) 
                          {
                              Q.pop();
                              Q.push(a[l1]);    
                          }     
                  }
                  l1++;
           }
           l2++;
    } 
    for (int i = l1; i <= cnt; i++) Q.push(a[i]);
    if (Q.size() < b[tot].x) printf("-1\n");
    else 
    {
        int ans = 0;
        while (Q.size()) 
        {
               ans += Q.top().x;
               Q.pop();
        }
        printf("%d\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值