可口蛋糕

题目描述
小蓝制作了 n n n 个蛋糕并将其从左往右排成一行,其中第 i i i 个蛋糕的饱腹度为 w i w_i wi 其可口值为 d i d_i di
由于手法过于生疏,尽管每个蛋糕的饱腹度必然为正数,但是可能存在蛋糕的可口值为负数!
作为可口蛋糕大赛的评委,小灰灰需要吃掉一段连续的蛋糕,使得蛋糕的饱腹度之和至少为 W W W

而小蓝的得分就是小灰灰吃掉蛋糕所对应的可口值之和,她想知道在小灰灰帮助她的情况下,她的最大可能得分是多少。
输入描述:
第一行两个空格分隔的整数分别代表 n n n W W W。接下来一行 n n n 个空格分隔的整数分别代表: w 1 , w 2 , . . . , w n w_1,w_2,...,w_n w1,w2,...,wn
再接下来一行 n n n 个空格分隔的整数分别代表: d 1 , d 2 , . . . , d n d_1,d_2,...,d_n d1,d2,...,dn。保证:
1 ≤ n ≤ 1 0 6 1\leq n\leq10^6 1n106
1 ≤ W , w i ≤ 1 0 9 1\leq W,w_i\leq10^9 1W,wi109
0 ≤ ∣ d i ∣ ≤ 1 0 9 0\leq|d_i|\leq10^9 0di109
W ≤ ∑ i = 1 n w i W\leq\sum_{i=1}^nw_i Wi=1nwi
输出描述:
输出一行一个整数代表答案。
示例1:
输入

5 8
1 4 5 2 3
-1 -1 1 -2 1

输出

0

分析:
我们知道饱腹度必然是正数,而可口度可能是负数,我们可以枚举当前节点i,找到饱腹度开始大于W的pos,那么pos后面的饱腹度必然也大于W,那么这时只需要寻找在pos之后可口度的最大值,如果直接暴力查找,时间复杂度是 O ( n 2 ) O(n^2) O(n2)的会超时,想想怎么优化,可以用一个md数组,记录从该节点之后的最大可口度,这样我们就能以 O ( 1 ) O(1) O(1)的复杂度找到最大可口度。
下面是完整代码

#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int N = 1e6 + 10; // 定义常量N为1e6 + 10,这是题目中给出的蛋糕数量的上限
ll n, w; // n表示蛋糕的数量,w表示小灰灰要求的最小饱腹度
ll sumw[N], sumd[N], md[N]; // sumw数组存储蛋糕的饱腹度前缀和,sumd数组存储蛋糕的可口值前缀和,md数组用于存储从当前位置到末尾最大可口值

int main(){
   cin >> n >> w;
   for(int i = 1; i <= n; i++){
       int x;
       cin >> x;
       sumw[i] = x + sumw[i-1]; // 计算饱腹度的前缀和
   }
   for(int i = 1; i <= n; i++){
       int x;
       cin >> x;
       sumd[i] = x + sumd[i-1]; // 计算可口值的前缀和
   }

   // md数组初始化为一个非常小的值(这里使用了-1e15)
   md[n+1] = -1e15;
   for(int i = n; i >= 1; i--){
       md[i] = max(md[i+1], sumd[i]); // 从后向前,维护当前位置i到末尾的最大可口值
   }

   ll res = -1e15; // 结果初始化为一个非常小的值(这里使用了-1e15)
   for(int i = 1; i <= n; i++){
       // 使用lower_bound找到第一个使得饱腹度之和至少为w的蛋糕位置,注意这里是sum[i-1]不是sum[i]
       int pos = lower_bound(sumw+1, sumw+n+1, sumw[i-1]+w) - sumw;
       // 更新结果,res为吃掉的蛋糕的可口值之和的最大值
       res = max(res, md[pos] - sumd[i-1]);
   }
   cout << res << endl; // 输出结果
   return 0;
}

补充:

for(int i = n;i>=1;i–){
md[i] = max(md[i+1],sumd[i]);
}
这个为什么要后序遍历

原因是:这里使用后序遍历(从后往前遍历)是为了建立一个从当前位置 i 到末尾的最大可口值数组 md。因为我们想要知道对于任意位置 i,从 i 到 n 这一段蛋糕中可口值之和的最大值是多少。这样当我们在后面寻找最大得分时,只需要查看 md[i] 就能快速得到从位置 i 开始到末尾的最大可口值之和。而用前序遍历的话明显要找的不是从当前位置 i 到末尾的最大可口值数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值