c++专题二学习日记
二分法
1.基本模版
(1)l<=r
int l,r,ans;while(l<=r){int mid=l+r >> 1;if(check(mid)) ans=mid,l=mid+1;else r=mid-1;}return ans;
(2)l<r
int l,r;while(l<r){int mid=l+r+1 >>1;if(check(mid)) l=mid;else r=mid-1;}return l;
or
while(l<r){int mid=l+r-1 >>1;if(check(mid))r=mid;else l=mid+1;}return r;
2.做题
(1)A-B数对
应该用二分查找符合A=B+C的A,不过我用了map就不改了
int main(){int n,c;cin>>n>>c;unordered_map<int,int> numbers;long long count=0;vector<int> a(n);int i;for(i=0;i<n;i++){cin>>a[i];numbers[a[i]+c]+=1;}sort(a.begin(),a.end()); //用algorithm中的sort排序数组afor(i=0;i<n;i++){count+=numbers[a[i]];}
cout<<count<<endl;return 0;
}
(2)抄书
思路:
[1]用贪心算法来check找到的mid可不可行(第1个人抄,抄到超过mid后换下一个人抄,以此类推;
[2]用二分找到mid;
[3]因为要让前面的人少抄,贪心要从后往前走
#include<iostream>
using namespace std;
const int K=500;
int m,k,mid;
int a[K+10],s[K+10],ed[K+10];
bool check(int mid){ //[1]int cnt=1,now=mid;int i;for(i=1;i<=m;i++){if(a[i]>now){cnt++;i--;now=mid;}elsenow-=a[i];}return cnt<=k;
}
int main(){cin>>m>>k;int i,max=0,sum=0;for(i=1;i<=m;i++){cin>>a[i];if(a[i]>max)max=a[i];sum+=a[i];}int l=max,r=sum;while(l<r){ //[2]mid=(l+r-1) >> 1;if(check(mid)){r=mid;}elsel=mid+1;}ed[k]=m;s[1]=1;int j,now=r; //[3]for(i=k,j=m;i>0;i--){for(;now>=a[j]&&j>0;j--){now-=a[j];}s[i]=j+1;ed[i-1]=j;now=r;}for(i=1;i<=k;i++){cout<<s[i]<<' '<<ed[i]<<endl;}return 0;}
(3)青蛙过河
思路:
假设青蛙跳跃长度为y,那么对任意一个区间[l,l+y-1],高度和一定大于2x。如果每段高度和都大于2x,那么对于0~n的任意一点a,都有大于等于2x种途径跳上a,所以只要保证任意一段长度为y的区间,高度和大于2x,青蛙跳跃能力为y时就可以上岸。
#include<iostream>
using namespace std;
const int N=100005;
int n,x;
int h[N];
long long s[N];
int l,r,mid;
bool check(int mid){int i;for(i=0;i+mid-1<n;i++){int j=i+mid-1;if(s[j]-s[i-1]<2*x)return false;}return true;
}
int main(){ //前缀和:cin>>n>>x; sum[1]=h[1]int i; sum[2]=h[1]+h[2]for(i=1;i<n;i++){ sum[3]=h[1]+h[2]+h[3]...cin>>h[i]; s[i]=s[i-1]+h[i]; [L,R]=sum[R]-sum[L-1]}l=1;r=n;while(l<r){mid=l+r >> 1;if(check(mid))r=mid;elsel=mid+1;}cout<<l<<endl;return 0;
}