SCUT 130:对抗女巫的魔法碎片(贪心)

https://scut.online/p/130

题目描述

光明世界的一个国家发生动荡,女巫利用了邪恶的力量将国家的村庄都施下了咒语,好在国家还有英勇的士兵,他们正义的力量能够破解这些魔咒夺回村庄,并且得到魔法碎片,利用足够多的魔法碎片可以将女巫铲除。

现在已经被魔咒封印的村庄有mm个,编号为11到mm。英勇的士兵nn个,编号从11到nn。第ii个士兵攻击力为a_iai​​,第jj个村庄防御力为b_jbj​​,魔法价值为c_ici​​。

现在这些士兵想夺回这些村庄,每个士兵可以最多占领一个村庄,一个村庄最多被一个士兵占领。当士兵的攻击力a_iai​​大于村庄的防御力b_jbj​​的时候,该士兵就可以夺回这个村庄,并且士兵会获得魔法碎片a_i - b_j + c_jai​​bj​​+cj​​ 个。

现在想知道这些士兵夺回村庄,获得的魔法碎片之和最多是多少。

输入格式

输入第一行一个整数TT,表示有TT组数据。

接下来一行输入两个整数nn和mm。

接下来一行,输入nn个数 a_iai​​,表示士兵的攻击力。

接下来mm行,每行输入两个数b_i,c_ibi​​,ci​​,表示村庄的防御力和该村庄的魔法价值。

1 \leq n, m \leq 1000001n,m100000

1 \leq a_i, b_i, c_i \leq 1000001ai​​,bi​​,ci​​100000

输出格式

一个整数,表示获得的魔法碎片的数量

样例数据

输入

2
3 3
4 4 4
2 3
1 3
5 3
3 3
4 4 6
2 3
4 3
5 3

输出

11
10

思路:贪心。首先因为能用更多的士兵去匹配更多的城堡更好,考虑如果当前有很多个士兵匹配一个城堡的情况,那么肯定是ai大的去匹配更好。
可以对a和b都从小到大排序,然后对于当前的士兵,将所有ai > bj的城堡都用cj - bj进入优先队列,然后对于这个士兵取堆顶,相当于当前士兵匹配堆顶这个城堡。
如果当前的士兵没找到城堡可以匹配,那么需要替换掉之前的士兵,即用更大的ai去匹配之前最小的ai对应的城堡,具体细节在代码中。
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define N 100010
 4 typedef long long LL;
 5 struct node {
 6     int b, c;
 7 } p[N];
 8 int a[N], ans[N];
 9 bool flag[N];
10 priority_queue<int> que;
11 
12 bool cmp(const node &a, const node &b) {
13     if(a.b != b.b) return a.b < b.b;
14     return a.c > b.c;
15 }
16 
17 int main() {
18     int t; scanf("%d", &t);
19     while(t--) {
20         int n, m; scanf("%d%d", &n, &m);
21         memset(ans, 0, sizeof(ans));
22         memset(flag, 0, sizeof(flag));
23         while(!que.empty()) que.pop();
24         for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
25         for(int i = 1; i <= m; i++) scanf("%d %d", &p[i].b, &p[i].c);
26         sort(p + 1, p + 1 + m, cmp);
27         sort(a + 1, a + 1 + n);
28         int now = 1, cancel = 1;
29         for(int i = 1; i <= n; i++) {
30             while(a[i] > p[now].b && now <= m) que.push(p[now].c - p[now].b), now++;
31             if(!que.empty()) {
32                 int top = que.top(); que.pop();
33                 flag[i] = 1; ans[i] = a[i] + top;
34             } else {
35                 while(!flag[cancel] && cancel < i) cancel++;
36                 if(flag[cancel]) ans[i] = ans[cancel] - a[cancel] + a[i], flag[i] = 1, flag[cancel] = 0, ans[cancel++] = 0;
37 //                printf("else : %d %d\n", i, cancel);
38             }
39         }
40         LL res = 0;
41         for(int i = 1; i <= n; i++) {
42 //            printf("%d : %d\n", i, ans[i]);
43             if(flag[i]) res += ans[i] > 0 ? ans[i] : 0;
44         }
45         printf("%lld\n", res);
46     }
47     return 0;
48 }
49 
50 /*
51 2
52 3 3
53 4 4 4
54 2 3
55 1 3
56 5 3
57 3 3
58 4 4 6
59 2 3
60 4 3
61 5 3
62 Êä³ö
63 
64 11
65 10
66 */
 
          

转载于:https://www.cnblogs.com/fightfordream/p/6788895.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值