前后前缀
一种特殊的前缀方法:
通过前后两次前缀,可以求出目的区间值
例题1:
最大或值:2680. 最大或值 - 力扣(LeetCode)(贪心+前缀)
贪心可知只让一个数变化最后或值最大,所以通过前后缀求出区间数,使得变化所有区间数求出最大就行
class Solution {
public:
long long maximumOr(vector<int>& nums, int k) {
int n=nums.size();
vector<long long>l(n+10,0);
vector<long long>r(n+10,0);
for(int i=1;i<=n;i++) l[i]=l[i-1] | nums[i-1];
for(int i=n-1;i>=0;i--) r[i]=r[i+1] | nums[i];
long long max1=0;
for(int i=0;i<n;i++)
{
long long current=(l[i] | r[i+1]) | ((long long)(nums[i]) << k);
max1=max(current,max1);
}
return max1;
}
};
例题2:
爱吃糖的小蓝:1.爱吃糖的小蓝 - 蓝桥云课 (前缀+二分)
先进行前后缀和计算,这样可以找到需要删除的中间糖果区间,然后在确定前区间的情况下二分优化找到后区间选择的糖果位置
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,h;
int a[1000010],pre[1000010],nex[1000010];
signed main()
{
cin>>n>>h;
for(int i=1; i<=n; i++) cin>>a[i];
for(int i=1; i<=n; i++)
{
pre[i]=pre[i-1]+a[i];
}
for(int i=n; i>=1; i--)
{
nex[i]=nex[i+1]+a[i];
}
if(pre[n]<=h)
{
cout<<pre[n]<<endl;
return 0;
}
int ans=0;
for(int i=0; i<=n; i++)
{
if(pre[i]>h) break;
int target=h-pre[i];
int index=lower_bound(nex+i+1,nex+n+1,target,greater<int>())-nex; //第一个不大于target的元素位置(-next+1是不小于) greater需要反方向找
if(index>n)
{
ans=max(ans,pre[i]);
}
else
{
ans=max(ans,pre[i]+nex[index]);
}
}
cout<<ans<<endl;
return 0;
}