二分+前缀和 牛客月赛86E题 可口蛋糕

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
 

小蓝制作了 n个蛋糕并将其从左往右排成一行,其中第 iii 个蛋糕的饱腹度为 wo 其可口值为 di​。

由于手法过于生疏,尽管每个蛋糕的饱腹度必然为正数,但是可能存在蛋糕的可口值为负数!

作为可口蛋糕大赛的评委,小灰灰需要吃掉一段连续的蛋糕,使得蛋糕的饱腹度之和至少为 W。

而小蓝的得分就是小灰灰吃掉蛋糕所对应的可口值之和,她想知道在小灰灰帮助她的情况下,她的最大可能得分是多少。

输入描述:

第一行两个空格分隔的整数分别代表 n 和 W。

接下来一行 n 个空格分隔的整数分别代表:w1,w2,...,wnw_1, w_2, ..., w_nw1​,w2​,...,wn​。

再接下来一行 n 个空格分隔的整数分别代表:d1,d2,...,dnd_1,d_2,...,d_nd1​,d2​,...,dn​。

保证:
1≤n≤1061 \le n \le 10^61≤n≤106 

1≤W,wi≤1091 \le W,w_i\le10^91≤W,wi​≤109

0≤∣di∣≤1090\le |d_i|\le10^90≤∣di​∣≤109

W≤∑i=1nwiW \le \sum_{i=1}^n w_iW≤∑i=1n​wi​

输出描述:

输出一行一个整数代表答案。

示例1

输入

复制5 8 1 4 5 2 3 -1 -1 1 -2 1

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

输出

复制0

0

说明

选择区间 [2,3][2,3][2,3] 或者区间 [3,5][3,5][3,5] 时,这段蛋糕的饱腹度之和都超过了 8,且其可口值之和均为 0,可以证明这就是小蓝能够获得的最大得分。

我们可以采用前缀和的方式来维护饱腹值 

通过下面的公式:

sumd[r] - sum[l-1] >= W

可以得到如果要饱腹的话,就有

sum[r] >= sum[l-1]+W

我们可以从1开始枚举每个l,就有与之对应的最小的r可以饱腹,我们可以从最小的r开始一直到n来查询最大的d,但是会超时,所以我们在用一个后缀最大值来维护d。

那么问题就是如何寻找最小的r 和维护后缀最大值。

我们可以使用二分查找进行寻找,可以使用c++自带库函数lower_bound进行寻找

int pos = lower_bound(sumw+1 ,sumw+n+1 , W+sumw[i-1])-sumw;

对于后缀最大值 ,使用一个数组mi进行维护

mi[n+1] =-1e15;
	for(int i =n;i>=1;--i){
		mi[i] = max(mi[i+1] , sumd[i]);
	}

此时就做好了全部工作

下面是ac代码

#include <bits/stdc++.h>
using namespace std;
using ll =long long;
const int N =1e6;
ll w[N] ,d[N],sumw[N] ,sumd[N] , mi[N];
int main(){
	int n,W;cin>>n>>W;
	for(int i =1;i<=n;++i)cin>>w[i] , sumw[i] = sumw[i-1] + w[i];  //前缀和处理 
	for(int i =1;i<=n;++i)cin>>d[i] , sumd[i] = sumd[i-1] + d[i];  //前缀和
	
	mi[n+1] =-1e15;
	for(int i =n;i>=1;--i){
		mi[i] = max(mi[i+1] , sumd[i]);
	}
	ll ans =-1e15;
	for(int i =1;i<=n;++i){
		int pos = lower_bound(sumw+1 ,sumw+n+1 , W+sumw[i-1])-sumw;
		ans = max(ans , mi[pos] - sumd[i-1]);
	} 
	cout<<ans;
	
	
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值