51nod 1105 第K大的数 (二分套二分 好题)
来源:互联网 发布:微量网 知乎 编辑:程序博客网 时间:2024/05/18 03:32
传送门:51nod 1105
3 21 22 33 4
9
思路:一看到题目,还以为是主席树求区间第 K 大值的题……然鹅是求 a、b 两数组相乘的值中第 K 大的。由于 N 很大,不能暴力求解,时间和空间都受不了。
一百度,原来有种二分套二分的方法是求解两个数组组合乘积的第 K 大值的。具体方法是先对 a、b 数组排序,然后外层对可能出现在 c 数组中的值 mid 进行二分,内层用二分求 c 数组中 >= 该值 mid 的数的个数,找到一个满足条件的最大值即答案。
注意:
1.数据很大,要用 long long 型。当两个 int 型整数相乘超过 int 型的值时需要至少两者之一是 long long 型,这时候只有最终值设为 long long 型是不行的哦~
2.对于二分搜索想再说几句。个人建议写二分的时候使用“左闭右开”的形式,例如,要对下标为 0~n-1 的 n 个数二分,则传参时保证左闭右开,即区间左端为0,右端为n。在判断二分终止条件时也是左闭右开,即 while( l < r ) .对于缩小区间时,也是左闭右开,即 if( a[mid] < val ) l=mid+1; if( a[mid] > val) r=mid;
其他形式不一定有错,但是上面这种是比较容易记忆的,一定没错。
代码:
#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>using namespace std;typedef long long LL;LL a[50010],b[50010];LL find(LL x,int n){ //查找c数组中 >=x 数的个数 int i,num;LL tp,sum=0;for(i=n-1;i>=0;i--){ //枚举a数组,寻找a[i]*b[j]中 <x 数的个数num if(x%a[i]) tp=x/a[i]+1;else tp=x/a[i];num=lower_bound(b,b+n,tp)-b;sum+=n-num;if(sum==0) break;}return sum;}int main(){int i,n,k;LL l,r,mid,tmp;while(~scanf("%d%d",&n,&k)){for(i=0;i<n;i++) scanf("%d%d",&a[i],&b[i]);sort(a,a+n);sort(b,b+n);l=a[0]*b[0]; //l为c数组中最小的数 r=a[n-1]*b[n-1]+1; //r为c数组中最大的数 while(l<r){ //二分 mid=(l+r)>>1;tmp=find(mid,n); //查找 >=mid 数的个数 if(tmp<k) r=mid; //如果个数<k,说明当前数太大 else l=mid+1;}printf("%lld\n",l-1);}return 0;}
看完代码了,你是不是和我一样,感觉有些地方好像看起来挺对的,但是想不通为什么是这样呢?
1.外层二分的时候 mid 的值一定会在 c 数组中吗?
其实在二分的过程中不一定能保证每个 mid 的值都在 c 数组中,我们只是用 mid 值来不断的逼近答案,答案ans一定是使得 c 数组中 >=ans 数的个数有 k 个的最大值。
2.内层二分的时候为什么要判断 x 是否能整除 a[i]?
原因很简单,因为我们要用 lower_bound 函数找的是 a[i]*b[j] < x 数的个数,如果 x%a[i]==0 直接找 < x%a[i] 的个数就好了,反之需要找 < x%a[i] + 1 的个数。
- 51nod 1105 第K大的数 (二分套二分 好题)
- 51 nod 1105 第K大的数 二分套二分
- 51NOD 1105 第K大的数(二分好题)
- 51nod 1105 第K大的数(二分)
- 51nod 1105 第K大的数【二分+思维】好题~
- 51nod 1105 第K大的数 (二分答案)
- 51NOD 1105 第K大的数 【二分】
- 51nod 1105 第K大的数【二分】
- 51Nod 1105 第k大的数 二分
- 51nod 1105 第K大的数 二分
- 51nod 1686 第K大区间 二分好题
- 51nod 1105---二分套二分
- 51nod 1105 二分套二分
- 1105 第K大的数 二分搜索
- 二分 51Nod1105 第K大的数
- 【51nod1105】【第K大的数】【二分答案】
- 51nod 1686 第K大区间【离散化+二分】
- 51nod 1686 第K大区间(二分 尺取)
- [数学理论]单一数字评估指标
- css中的em
- 初识Oracle
- 让Block顺序执行
- 数据的归一化
- 51nod 1105 第K大的数 (二分套二分 好题)
- poj 3070 Fibonacci
- 一行 Shell 通过 Nginx access 日志实时统计单台机器QPS
- android java 接口回调
- jeecg中上传附件的处理
- 扩展vim遇到的问题-windows与linux的文件格式问题
- python学习教程
- 0基础lua学习(六)控制语句
- 初步了解在线测试系统