链接:登录—专业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=1nwi
输出描述:
输出一行一个整数代表答案。
示例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;
}