金发姑娘和N头牛
作者:互联网
金发姑娘和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