学习总结--二分
前提是有序(即单调),若无序一般先sort
向左找
while(l int mid = (l+r)/2; if(a[mid]>=x) r=mid; else l=mid+1; } 向右找 while(l int mid = (l+r)/2; if(a[mid]<=x) l=mid; else r=mid-1; } 懒得写时可以直接 lower_bound() upper_bound() binary_search() 模板简单,难点是check函数的编写 while(l<=r){ int mid = (l+r)/2; if(check(mid)) l=mid+1; else r=mid-1; } 根据题目变更l与r 洛谷P8775青蛙过河 青蛙可以跳1~L距离,求最多可以跳几次,就是取区间1~L高度和的最小值 洛谷P8775青蛙过河解题思路及代码 总体思路挺清晰的,将1到n区间二分答案,难点在于如何写check函数,分析可知从河左边与右边走是一样的,即只要青蛙可以过河的次数大于等于2x就行,青蛙可以跳1~mid的距离,要保证青蛙在此区间内每一次都可以有落脚点,就是取mid区间内高度和最小值,即取最小前缀和,至此思路完整 AC代码: #include using namespace std; int n; long long x; long long a[100001]; bool check(int mid){ long long sum=0,minn=1e10; for(int i=1;i for(int i=mid;i sum+=a[i]; minn=min(sum,minn); sum-=a[i-mid+1]; } if(minn>=2*x) return 1; else return 0; } int main(){ cin>>n>>x; for(int i=1;i int l=1,r=n,ans; while(l<=r){ int mid=(l+r)/2; if(check(mid)) ans=mid,r=mid-1; else l=mid+1; } cout< return 0; } 洛谷P1281书的复制解题思路及代码 总体思路还是二分答案,代码可以分为三部分,check二分和划分每个人抄写范围。首先明确二分区间,l为1,r为复制有书的总时间,接下来写check函数,比较恶心的一点是输出让前面的人尽可能少写,所以写check时得从后往前遍历,用count来记录按不超过mid的时间需要几人,若count<=题目给定人数,往左找,大于往右找,最后再根据所求时间从后往前进行划分,输出,思路完整,按思路和题目模拟就行 AC代码: #include using namespace std; long long sum=0; int n,k,a[502],b[502][2]; bool check(int mid){ long long sum2=0; int count=0; for(int i=n;i>=1;i--){ sum2+=a[i]; if(sum2>mid&&i!=1){ sum2=a[i]; count++; } if(i==1){ if(sum2>mid) count+=2; else count++; } } if(count<=k) return 1; else return 0; } int main(){ cin>>n>>k; for(int i=1;i<=n;i++) cin>>a[i],sum+=a[i]; int l=1,r=sum,ans; while(l<=r){ int mid=(l+r)/2; if(check(mid)) ans=mid,r=mid-1; else l=mid+1; } int num=k,y=n,sum2=0; for(int i=n;i>=1;i--){ sum2+=a[i]; if(sum2>ans&&i!=1){ b[num][0]=i+1; b[num][1]=y; sum2=a[i]; num--; y=i; } if(i==1&&sum2>ans){ b[2][0]=2,b[2][1]=y,b[1][0]=1,b[1][1]=1; }else{ b[1][0]=1,b[1][1]=y; } } for(int i=1;i<=k;i++) cout<
return 0; } 洛谷P8800卡牌解题思路及代码 二分,第一明确查找区间即1~大于最大卡牌数的任意数(尽量开大),接下来作些准备工作(个人做法),先贪心,对记录数据的结构体排个序,可以节省check的循环次数,接着是关键的check,从最少的牌数开始遍历,与套数mid进行比较,若小于mid,判断能否补到mid,可以,continue,否则直接break,check结束,若大于等于因为已经排好序后面肯定也大于等于check结束, AC代码 #include using namespace std; struct pai{ int a; int b; }; struct pai c[200002]; long long n,m; bool cmp(pai s1,pai s2){ return s1.a } bool check(int mid){ long long sum=m,flag=2; for(int i=1;i<=n;i++){ if(c[i].a if(c[i].b>=mid-c[i].a&&sum>=mid-c[i].a){ sum=sum+c[i].a-mid; if(i==n) flag=1; }else{ flag=0; break; } }else{ flag=1; break; } } if(flag==0) return 0; else if(flag==1) return 1; } int main(){ cin>>n>>m; for(int i=1;i<=n;i++) cin>>c[i].a; for(int i=1;i<=n;i++) cin>>c[i].b; sort(c+1,c+n+1,cmp); int l=1,r=2e6,ans; while(l<=r){ int mid=(l+r)/2; if(check(mid)) ans=mid,l=mid+1; else r=mid-1; } cout< return 0; } 洛谷P8647分巧克力解题思路及代码 题单里最简单的二分查找,套资料模板就行,直接上AC代码 #include using namespace std; int a[100001][2],n,k; bool check(int mid){ int cnt=0; for(int i=1;i<=n;i++) cnt+=(a[i][0]/mid)*(a[i][1]/mid); if(cnt>=k) return 1; else return 0; } int main(){ cin>>n>>k; for(int i=1;i<=n;i++) cin>>a[i][0]>>a[i][1]; int l=1,r=1e5,ans; while(l<=r){ int mid=(l+r)/2; if(check(mid)) ans=mid,l=mid+1; else r=mid-1; } cout< return 0; } 洛谷P1102A-B数对解题思路及代码 三个月前写的,现在只记得大致思路,二分查找,第一步sort排序,然后两次二分查找,找小于等于a[i]-C的和小于a[i]+C的,最后用sum累加和 AC代码 #include using namespace std; const long long y=1000010; long long w[y],n,m,mm,nn,sum=0; int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ cin>>w[i]; } sort(w+1,w+1+n); for(int i=1;i<=n;i++){ int l=1,r=n; while(l int mid=(l+r)/2; if(w[mid]-w[i]>=m){ r=mid; }else{ l=mid+1; } } if(w[l]-w[i]==m){ mm=l; }else{ continue; } l=mm-1,r=n; while(l int mid=(l+r+1)/2; if(w[mid]-w[i]<=m){ l=mid; }else{ r=mid-1; } } if(w[l]-w[i]==m){ nn=l; }else{ continue; } sum+=nn-mm+1; } cout< return 0; } 51Nod-2063二分查找解题思路及代码 水题,套模板或直接binary_search(),上代码 #include using namespace std; long long a[100002]; int n,q; int main(){ cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; cin>>q; for(int i=1;i<=q;i++){ long long x; cin>>x; if(binary_search(a+1,a+n+1,x)){ cout<<"Yes"< }else{ cout<<"No"< } } return 0; }