接下来我们开始寻找符合要求的区间,如果只求通过的话,可以运用二分思想。依次从 $x_1$ 开始一直遍历到 $x_R$ 查找区间的左端点,之后二分查找每一个左端点 $x_i$ 对应的右端点 $x_j$ 使得收获的农田最多。
代码如下:
```cpp
#include<cstdio>
#include<cstdlib>
using namespace std;
const int SIZE=1e5+5;
long long R,L,B,ans,mid;
long long x[SIZE],sum[SIZE];
inline long long max(long long a,long long b){
if(a>b) return a;
else return b;
}
long long check(long long l,long long r){
mid=l+r>>1;
return x[mid]*(mid*2-l-r)+sum[l-1]+sum[r]-sum[mid]-sum[mid-1];
}
int main(){
scanf("%lld%lld%lld",&R,&L,&B);
for(long long i=1;i<=R;i++){
scanf("%lld",&x[i]);
sum[i]=sum[i-1]+x[i];
}
long long l,r,mid,k;
for(long long i=1;i<=R;i++){
l=i;r=R;
while(l<=r){
mid=l+r>>1;
if(check(i,mid)<=B){
l=mid+1;k=mid;
}
else r=mid-1;
}
ans=max(ans,k-i+1);
}
printf("%lld",ans);
return 0;
}
```
附[通过记录](https://www.luogu.com.cn/record/40865413)
而对于双向指针,其思想也相当简单。初始时选定区间 $[x[1],x[1]]$(此时花费为0,肯定满足要求)。 接下来把第二个 $x[1]$ 的下标右移,每右移一次判断一次。当总花费超过 $B$ 时则将第一个 $x[1]$ 的下标右移一,然后再判断总花费是否满足要求,是则右移右端点,否则右移左端点,以此类推,得到结果。(其正确性基于输入的 $x_i$ 单调递增,故右端点不需要在左端点右移后左移)
```cpp
#include<cstdio>
#include<cstdlib>
using namespace std;
const int SIZE=1e5+5;
long long R,L,B,ans,mid;
long long x[SIZE],sum[SIZE];
inline long long max(long long a,long long b){
if(a>b) return a;
else return b;
}
long long check(long long l,long long r){
mid=l+r>>1;
return x[mid]*(mid*2-l-r)+sum[l-1]+sum[r]-sum[mid]-sum[mid-1];
}
int main(){
scanf("%lld%lld%lld",&R,&L,&B);
for(long long i=1;i<=R;i++){
scanf("%lld",&x[i]);
sum[i]=sum[i-1]+x[i];
}
for(long long l=1,r=1;l<=R;l++){
while(r<R&&check(l,r+1)<=B) ++r;
//此处r忽略了 [x[1],x[1]] 的区间,并以 r+1 和 r<R作为判断依据
//是为了便于计算ans
ans=max(ans,r-l+1);
}
printf("%lld",ans);
return 0;
}
```
附[通过记录](https://www.luogu.com.cn/record/40865445)
代码中与详解不同的部分已用注释阐明。本题的重难点其实是在 check 函数里,请各位小心,不要错估其难度所在。
最后:如有疑问欢迎提出,木头酱看到后会回复在评论区。
以上,希望这篇题解能够帮到泥们QWQ