zoukankan      html  css  js  c++  java
  • 二分例题 51nod

    例题1  

    1010 只包含因子2 3 5的数

    http://www.51nod.com/Challenge/Problem.html#problemId=1010

    K的因子中只包含2 3 5。满足条件的前10个数是:2,3,4,5,6,8,9,10,12,15。

    所有这样的K组成了一个序列S,现在给出一个数n,求S中 >= 给定数的最小的数。

    例如:n = 13,S中 >= 13的最小的数是15,所以输出15。

     

    输入

    第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 10000)
    第2 - T + 1行:每行1个数N(1 <= N <= 10^18)

    输出

    共T行,每行1个数,输出>= n的最小的只包含因子2 3 5的数。

    输入样例

    5
    1
    8
    13
    35
    77

    输出样例

    2
    8
    15
    36
    80
    题解 :这个题目用到二分,二分之前需要预处理一个数组
    定理:K=2^x*3^y*5^z即k是只包含2,3,5,的因子的数
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll inf =1e18+10000;//这里的范围要比1e8大1000左右
    const int N=1E6+7;
    ll arr[N];
    int pos=0;
    void inint(){
        ll i, j, k;
        for(i=1;i<inf;i*=2)
            for(j=1;j*i<inf;j*=3)
                for(k=1;k*i*j<inf;k*=5)
                    arr[pos++]=i*j*k;
    }
    int main(){
        inint();
        sort(arr,arr+pos);
        int t;
        scanf("%d",&t);
        while(t--){
            ll n;
            cin>>n;
            ll ans;
            int left=1;
            int right=pos-1;
            while(left<=right){
                int mid=(left+right)/2;
                if(arr[mid]>=n){
                    ans=arr[mid];
                    right=mid-1;
                }
                else {
                    left=mid+1;
                }
            }
            cout<<ans<<endl;
        }
        
        return 0;
    } 

    例题2

    1267 4个数和为0

    http://www.51nod.com/Challenge/Problem.html#problemId=1267

    给出N个整数,你来判断一下是否能够选出4个数,他们的和为0,可以则输出"Yes",否则输出"No"。
     

    输入

    第1行,1个数N,N为数组的长度(4 <= N <= 1000)
    第2 - N + 1行:A[i](-10^9 <= A[i] <= 10^9)

    输出

    如果可以选出4个数,使得他们的和为0,则输出"Yes",否则输出"No"。

    输入样例

    5
    -1
    1
    -5
    2
    4

    输出样例

    Yes
    题解:要找4个数,这四个数的和为0,我们先确定好两个数,然后再二分查找另外两个数
    #include<bits/stdc++.h>
    using namespace std;
    const int N=1000+7;
    int arr[N];
    int main(){
        int t;
        cin>>t;
        for(int i=0;i<t;i++) scanf("%d",&arr[i]);
        sort(arr,arr+t);
        bool flag=false ;
        for(int i=0;i<t;i++){
            for(int j=i+1;j<t;j++){
                for(int k=j+1;k<t;k++){
                    int ans=arr[i]+arr[j]+arr[k];
                    int left=k+1;
                    int right=t-1;
                    while(left<=right){
                        int mid=(left+right)/2;
                        if(arr[mid]+ans>0){
                            right=mid-1;
                        }
                        else if(arr[mid]+ans<0){
                            left=left+1;
                        }
                        else {
                            flag=true;
                            break;
                        }
                    }
                    if(flag) break;
                }
                if(flag) break;
            }
            if(flag) break;
        }
        if(flag) puts("Yes");
        else puts("No");
        return 0;
    }

    例题3

    1105 第K大的数

    http://www.51nod.com/Challenge/Problem.html#problemId=1105

    数组A和数组B,里面都有n个整数。

    数组C共有n^2个整数,分别是:

    A[0] * B[0],A[0] * B[1] ...... A[0] * B[n-1]

    A[1] * B[0],A[1] * B[1] ...... A[1] * B[n-1] 

    ...... 

    A[n - 1] * B[0],A[n - 1] * B[1]  ......  A[n - 1] * B[n - 1]

    是数组A同数组B的组合,求数组C中第K大的数。

    例如:

    A:1 2 3,B:2 3 4。

    A与B组合成的C为

             A[0]  A[1]  A[2]

    B[0]     2      3      4

    B[1]     4      6      8

    B[2]     6      9     12

    共9个数。

     

    输入

    第1行:2个数N和K,中间用空格分隔。N为数组的长度,K对应第K大的数。(2 <= N <= 50000,1 <= K <= 10^9)
    第2 - N + 1行:每行2个数,分别是A[i]和B[i]。(1 <= A[i],B[i] <= 10^9)

    输出

    输出第K大的数。

    输入样例

    3 2
    1 2
    2 3
    3 4

    输出样例

    9
    题解 二分套二分。传统的二分都是对排好序的数组的下标进行处理,这里不一样,我们二分的left为最小值,right为最大值,然后二分这个区间,同时判断大于mid的个数,当大于mid的个数为m-1时,就是答案。但是不一定是最优的答案,所以要继续增大,继续查找
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N= 50000+7;
    ll arr1[N],arr2[N];
    int n,m;
    ll sum(ll x){
        ll sum1=0;
        for(int i=0;i<n;i++){
            int left=0;
            ll ans=n;
            int right=n-1;
            while(left<=right){
                int mid=(left+right)/2;
                if(arr1[i]*arr2[mid]>x){
                    right=mid-1;
                    ans=mid;
                }
                else {
                    left=mid+1;
                }
            }
            sum1+=n-ans;
        }
        return sum1;
    }
    int main(){
        cin>>n>>m;
        for(int i=0;i<n;i++)    scanf("%lld%lld",&arr1[i],&arr2[i]);
        sort(arr1,arr1+n);
        sort(arr2,arr2+n);
        ll left=arr1[0]*arr2[0];
        ll ans=0;
        ll right=(1ll*arr1[n-1])*(1ll*arr2[n-1]); 
        while(left<=right){
            ll mid=(left+right)/2;
            ll x=sum(mid);
    //        if(x==m-1){
    //            ans=mid;
    //            right=mid-1;
    //        }  //这里这样写有点不对,因为我们的sum函数只是保存了比mid大的数的个数,但是当出现两个相等的数时,比他们大的数的数目是一样的,但是这两个数的位置不一样,一个在前边,一个在后边
            if(x<m){ 
                ans=mid;
                right=mid-1;
            }
            else {
                left=mid+1;
            }
        }
        cout<<ans<<endl;
        return 0;
    }


  • 相关阅读:
    揭秘淘宝286亿海量图片存储与处理架构
    从能做的事做起,做越来越多的事
    用表驱动代替switchcase
    文件过滤驱动中的重入处理
    谈谈对APC的一点理解
    StartIo例程的作用
    C++各大名库的介绍
    IRQL
    FastIO
    一道面试题,看这段代码最后抛出什么异常
  • 原文地址:https://www.cnblogs.com/Accepting/p/11507735.html
Copyright © 2011-2022 走看看