牛客小白月赛96 c题 补题

二分的思路是想出来了的啊,就是又被二分的边界搞心态了

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

题意就是在数组中找三段数组,其中中间的数组总值最大,问一共有多少组

比赛中的代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main()
{
     int n;
      cin>>n;
       vector<int>v(n+1),pri(n+1,0);
        for(int i=1;i<=n;i++){
            cin>>v[i];
            pri[i]=pri[i-1]+v[i];
        }

         int ans=0;
        for(int i=2;i<=n-1;i++){//二分范围[i,n-1]
            //pri[i-1],pri[mid]-pri[i-1],pri[n]-pri[mid]
            int l=i-1,r=n;
            //l=i,r=n-1 这样我觉得是对的
             while(l<r){
                 int mid=(l+r)/2;
                  if(pri[mid]-pri[i-1]>pri[i-1] && pri[mid]-pri[i-1]>pri[n]-pri[mid]){
                      r=mid;
                      ans++;
                  }
                  else{//不满足,中间的小了
                      l=mid+1;
                  }
             }
        }
         cout<<ans<<endl;
    return 0;
}

正确代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main()
{
    int n;
     cin>>n;
      vector<int>v(n+1),pri(n+1,0);
       for(int i=1;i<=n;i++){
           cin>>v[i];
           pri[i]=pri[i-1]+v[i];
       }

         int cnt=0;
        for(int i=1;i<=n-2;i++){
            int l=i+1,r=n-1,ans=-1;
            int a1=pri[i];
             while(l<=r){//如果l==r且为正确答案则记录,若l<r 则记录不到
                 int mid=(l+r)>>1;
                 int a2=pri[mid]-pri[i],a3=pri[n]-pri[mid];
                  if(a2>a1 && a2>a3){
                      ans=mid;//记录答案
                       r=mid-1;//为了寻找最左边的答案,此时记录了可能的最左边答案记录了,继续二分看左边是否还有更优答案
                  }
                  else{
                      l=mid+1;
                  }
             }
              if(ans!=-1) cnt+=(n-1)-ans +1;
        }
             cout<<cnt<<'\n';
    return 0;
}

正解是个整数二分,答案范围是[i+1,n-1]。如果i满足山峰条件,则i+1一定满足,所以为了找到完整的答案区间,就是要二分到左边第一个满足山峰条件的位置ans,这样ans到n-1都是满足的。

 所以就是个寻找最左边。

 其中的细节 while(l<=r) ,  ans=mid,r=mid-1 在代码中详细注释了,至于为什么不是(l+r+1)>>1有待思考。

  • 18
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值