ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

金发姑娘和N头牛

2022-02-06 13:32:07  阅读:168  来源: 互联网

标签:金发 right 头牛 int 姑娘 ret leq alls left


金发姑娘和N头牛

你可能听过关于金发姑娘和三只熊的经典故事。

然而,鲜为人知的是,金发姑娘最终成了一个农民。

在她的农场中,她的牛棚里有$N$奶牛。

不幸的是,她的奶牛对温度相当敏感。

对于奶牛$i$,使其感到舒适的温度为$A_{i}…B_{i}$。

如果金发姑娘将牛棚的恒温器的温度$T$设置为$T < A_{i}$,奶牛就会觉得冷,并会产出$X$单位的牛奶。

如果她将恒温器的温度$T$设置在$A_{i} \leq T \leq B_{i}$,奶牛就会感到舒适,并会产出$Y$单位的牛奶。

如果她将恒温器的温度$T$设置为$T > B_{i}$,奶牛就会觉得热,并会产出$Z$单位的牛奶。

正如所期望的那样,$Y$的值始终大于$X$和$Z$。

给定$X$,$Y$,$Z$以及每头奶牛感到舒适的温度范围,请计算通过合理设定恒温器温度,金发姑娘可获得的最大产奶量。

恒温器温度可设置为任何整数。

输入格式

第一行包含四个整数$N$,$X$,$Y$,$Z$。

接下来$N$行,每行包含两个整数$A_{i}$和$B_{i}$。

输出格式

输出可获得的最大产奶量。

数据范围

$1 \leq N \leq 20000$,
$0 \leq X, Y, Z \leq 1000$,
$0 \leq A_{i} \leq B_{i} \leq {10}^{9}$

输入样例:

4 7 9 6
5 8
3 4
13 20
7 10

输出样例:

31

样例解释:

金发姑娘可以将恒温器温度设置为$7$或$8$,这样会让奶牛$1$和$4$感到舒适,奶牛$2$感到热,奶牛$3$感到冷。

共可获得$31$单位牛奶。

 

解题思路

  题目意思大概就是,在一个无限长的数轴上给定一个区间,然后在该区间上的任取一个值(温度),对答案(产量)的贡献为$y$。如果在这个区间的左部分取值的话,则对答案的贡献为$x$。如果在这个区间的右部分取值的话,则对答案的贡献为$z$。

  等价于给每个区间都加上对应的数值,可以联想到差分。 

  这题给的$N$的数据范围很小,但值域却很大。实际上我们会用到的下标的值不会超过$2N$个,因此可以进行离散化。

  用差分数组得到原数组的话,其实是求差分数组的前缀和。值为$0$的位置其实可以不用管,因为$0$对前缀和没有影响。所以求最大值的时候可以把所有的$0$全部跳过。这意味着求前缀和的时候,只需要用所有出现过的数就可以了。因此我们只需要存区间的左右端点的下标就可以了。

  这里可以用map实现,$key$是下标,$value$是$x$或$y$或$z$。并且在遍历的时候,map会实现$key$的有序排序,因此可以用map来实现离散化。

  AC代码如下:

 1 #include <cstdio>
 2 #include <map>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 const int INF = 2e9;
 7 
 8 map<int, int> mp;
 9 
10 int main() {
11     int n, x, y, z;
12     scanf("%d %d %d %d", &n, &x, &y, &z);
13     for (int i = 0; i < n; i++) {
14         int left, right;
15         scanf("%d %d", &left, &right);
16 
17         mp[-INF] += x, mp[left] -= x;
18         mp[left] += y, mp[right + 1] -= y;
19         mp[right + 1] += z, mp[INF] -= z;
20     }
21 
22     int sum = 0, ret = 0;
23     for (auto &it : mp) {
24         sum += it.second;
25         ret = max(ret, sum);
26     }
27     printf("%d", ret);
28 
29     return 0;
30 }

  用map实现的话常数会比较大,运行效率没有手写高,因此下面给出手写实现离散化的方式。

  • 先把每次用到的左右下标分别存储到数组$l$和$r$中。
  • 同时把所有的下标都存储到$alls$中。然后进行排序,去重。这时所有会用到的下标会按大小顺序映射到$0, 1, ...$,达到保序的效果。
  • 接着遍历一遍数组$l$和$r$,通过二分找到映射后的下标,在差分数组$b$对应的左右区间端点进行操作。
  • 最后对差分数组求一遍前缀和,最大的值就是答案。

  AC代码如下:

 1 #include <cstdio>
 2 #include <vector>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 const int N = 2e4 + 10, INF = 2e9;
 7 
 8 vector<int> alls;
 9 int l[N], r[N], b[2 * N];
10 
11 int find(int x) {
12     int left = 0, right = alls.size() - 1;
13     while (left < right) {
14         int mid = left + right >> 1;
15         if (alls[mid] >= x) right = mid;
16         else left = mid + 1;
17     }
18 
19     return left;
20 }
21 
22 int main() {
23     int n, x, y, z;
24     scanf("%d %d %d %d", &n, &x, &y, &z);
25     for (int i = 0; i < n; i++) {
26         scanf("%d %d", l + i, r + i);
27         alls.push_back(l[i]), alls.push_back(r[i] + 1);
28     }
29     alls.push_back(-INF), alls.push_back(INF);
30 
31     sort(alls.begin(), alls.end());
32     alls.erase(unique(alls.begin(), alls.end()), alls.end());
33 
34     for (int i = 0; i < n; i++) {
35         int left = find(l[i]), right = find(r[i] + 1);
36         b[0] += x, b[left] -= x;
37         b[left] += y, b[right] -= y;
38         b[right] += z, b[alls.size() - 1] -= z;
39     }
40 
41     int sum = 0, ret = 0;
42     for (int i = 0; i < alls.size() - 1; i++) {
43         sum += b[i];
44         ret = max(ret, sum);
45     }
46     printf("%d", ret);
47 
48     return 0;
49 }

 

参考资料

  AcWing 1952. 金发姑娘和 N 头牛(寒假每日一题2022):https://www.acwing.com/video/3667/

标签:金发,right,头牛,int,姑娘,ret,leq,alls,left
来源: https://www.cnblogs.com/onlyblues/p/15865495.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有