• 二分经典例题


    整数二分:

    题目链接:http://oj.daimayuan.top/course/22/problem/59

    板子题:

    1. #include
    2. using namespace std;
    3. const int N=2e6+10;
    4. int a[N],n,q;
    5. int calc1(int x){//查找第一个小于x的位置
    6. int L=0,R=n+1;
    7. while(L+1
    8. int mid=L+R>>1;
    9. if(a[mid]
    10. else R=mid;
    11. }
    12. return L;
    13. }
    14. int calc2(int x){//查找第一个小于等于x的位置
    15. int L=0,R=n+1;
    16. while(L+1
    17. int mid=L+R>>1;
    18. if(a[mid]<=x) L=mid;
    19. else R=mid;
    20. }
    21. return L;
    22. }
    23. inline void solve(){
    24. cin>>n>>q;
    25. for(int i=1;i<=n;i++) cin>>a[i];
    26. sort(a+1,a+1+n);
    27. while(q--){
    28. int x;cin>>x;
    29. int x1=calc1(x),x2=calc2(x);
    30. cout<" "<" "<"\n";
    31. }
    32. }
    33. int main(){
    34. solve();
    35. }

     题目链接:http://oj.daimayuan.top/course/22/problem/61

    题意:给定一个长度为N的数组,以及最大操作次数K,求经过M次操作后使得数列中的最小值最大。

    思路:要想使得最小值最大,那么一定是经过了K次操作,这里直接二分答案,通过答案来求解操作数

    代码:

    1. #include
    2. using namespace std;
    3. const int N=2e6+10;
    4. int a[N],n,k;
    5. bool check(int x){//检查答案是否符合条件
    6. int ans=0;
    7. for(int i=1;i<=n;i++)
    8. ans+=max(0,x-a[i]);
    9. return ans<=k;
    10. }
    11. int main(){
    12. cin>>n>>k;
    13. for(int i=1;i<=n;i++) cin>>a[i];
    14. int L=0,R=n+1;
    15. while(L+1//二分答案
    16. int mid=L+R>>1;
    17. if(check(mid)) L=mid;
    18. else R=mid;
    19. }
    20. cout<
    21. }

    题目链接:http://oj.daimayuan.top/course/22/problem/649

    方法: 二分,怎么二分?

    因为把所有序列给合并起来,再算和,是一定会TIE的。

    如果可以求出每个序列都能满足条件的和,再把所有序列的和加起来,就好了。

     那么我们找出了位置,如何求和呢?

    直接采用等差数列的公式进行O(1)求和:n*(a1+an)/2

    代码:

    1. #include
    2. #define int long long
    3. using namespace std;
    4. const int N=2e5+10;
    5. int n,k[N],b[N],m;
    6. int calc(int z){//计算边界L左边小于等于z的个数
    7. int res=0;
    8. for(int i=1;i<=n;i++){
    9. if(z>=b[i]){
    10. //kx+b=z--->x=(z-b)/k
    11. int y=(z-b[i])/k[i]+1;//记录个数
    12. //为什么要加1,是因为每组序列中,都存在x=0的情况
    13. res+=y;//记录个数
    14. }
    15. }
    16. return res;
    17. }
    18. int sum(int z){
    19. int res=0;
    20. for(int i=1;i<=n;i++){
    21. if(z>=b[i]){
    22. int y=(z-b[i])/k[i] + 1;//记录项数
    23. res+=1LL*((b[i]+(y-1)*k[i]+b[i])*y/2);//记录每个序列中的和
    24. //等差数列求和公式:n*(a1+an)/2
    25. }
    26. }
    27. return res;
    28. }
    29. signed main(){
    30. cin>>n;
    31. for(int i=1;i<=n;i++) cin>>k[i]>>b[i];
    32. cin>>m;
    33. int L=0,R=1e14;//R尽可能的大
    34. while(L+1//二分
    35. int mid=L+R>>1;
    36. if(calc(mid)<=m) L=mid;
    37. else R=mid;
    38. }
    39. int ans=sum(L)+1LL*((m-calc(L))*(L+1));//最终答案
    40. cout<
    41. }

    浮点数二分:

    这里稍微讲一下:浮点数二分其实和整数二分是差不多的。唯一不同点在于:整数的二分次数是不确定的,而浮点数二分一般是能够算出来的,但是浮点数二分一般二分100次就可以了。 

    题目链接:http://oj.daimayuan.top/course/22/problem/648

    思路:二分答案。对于方向移动问题,我们可以考虑成区间的问题解答。 

    举个例子:a b人在两个不同点,他们要达到目标点,给定两人的速度,问最少能够到达?

    我们发现,只要两人跑到路程区间有交集,那么就可以到达,最少时间为跑的慢的人刚好到达目标点的时间。

    那么为什么跑的快的人不会超过目标位置呢?

    因为跑的快的人到达目标点后,是可以原地踏步的,就相当于在原地跑。(奇怪的知识又增加了Q_Q) 

    同理:多人跑目标位置,也是一样的道理。每一次都要改变交集,以保持最优情况

    代码:

    1. #include
    2. using namespace std;
    3. const int N=2e5+10;
    4. int n;
    5. int pos[N],v[N];
    6. bool check(double x){
    7. double L=-1e10,R=1e10;//初始区间尽可能大
    8. for(int i=1;i<=n;i++){
    9. double l=pos[i]-v[i]*x,r=pos[i]+v[i]*x;//求左右距离
    10. L=max(L,l);R=min(R,r);//求交集
    11. }
    12. if(L>R) return false;//若无交集
    13. return true;//有交集
    14. }
    15. signed main(){
    16. cin>>n;
    17. for(int i=1;i<=n;i++) cin>>pos[i]>>v[i];
    18. double L=0,R=5e4;//定义二分时间的区间//需根据题意自行判断区间
    19. for(int i=1;i<=100;i++){//二分次数100次
    20. double m=(L+R)/2;
    21. if(check(m)) R=m;
    22. else L=m;
    23. }
    24. cout<setprecision(10)<//输入L,R都可以
    25. }

     二分+哈希求字符串最长回文子串的长度,我们秉着最优的方法,这里就不讲了。

    二分+哈希:O(nlogn)    manacher:O(n) 

    题目链接:http://oj.daimayuan.top/course/22/problem/698

    二分求Lis(最长上升子序)也不讲了。秉着最优原则

    题目链接: http://oj.daimayuan.top/course/22/problem/647

  • 相关阅读:
    ASP.NET Core使用记录3
    信号处理之巴特沃斯滤波器的理解----2022/11/30
    JDK 21的新特性总结和分析
    【Webpack】CSS 处理
    Raymarching(光线步进)基础
    OpenGL笔记九之彩色三角形与重心插值算法
    Spring-Cloud-OpenFeign源码解析(上篇)
    OpenCV类VideoCapture构造函数中参数apiPreference的可选值及意义
    Python 基于 selenium 实现不同商城的商品价格差异分析系统
    常用软件快捷键
  • 原文地址:https://blog.csdn.net/YuDuna/article/details/127802224