二分的思路是想出来了的啊,就是又被二分的边界搞心态了
链接:登录—专业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有待思考。