金发姑娘和N头牛

金发姑娘和N头牛

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

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

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

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

对于奶牛i,使其感到舒适的温度为AiBi

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

如果她将恒温器的温度T设置在AiTBi,奶牛就会感到舒适,并会产出Y单位的牛奶。

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

正如所期望的那样,Y的值始终大于XZ

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

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

输入格式

第一行包含四个整数NXYZ

接下来N行,每行包含两个整数AiBi

输出格式

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

数据范围

1N20000,
0X,Y,Z1000,
0AiBi109

输入样例:

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

输出样例:

31

样例解释:

金发姑娘可以将恒温器温度设置为78,这样会让奶牛14感到舒适,奶牛2感到热,奶牛3感到冷。

共可获得31单位牛奶。

 

解题思路

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

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

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

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

  这里可以用map实现,key是下标,valuexyz。并且在遍历的时候,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实现的话常数会比较大,运行效率没有手写高,因此下面给出手写实现离散化的方式。

  • 先把每次用到的左右下标分别存储到数组lr中。
  • 同时把所有的下标都存储到alls中。然后进行排序,去重。这时所有会用到的下标会按大小顺序映射到0,1,...,达到保序的效果。
  • 接着遍历一遍数组lr,通过二分找到映射后的下标,在差分数组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/

 
posted @   onlyblues  阅读(117)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示