二分例题 51nod

匿名 (未验证) 提交于 2019-12-03 00:03:02

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同数组B的组合,求数组C中第K大的数。

例如:

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

A与B组合成的C为

共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; }

 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!