zoj3617(二分)

8G Island

Time Limit: 3 Seconds       Memory Limit: 32768 KB

8g Island has N boys and M girls. Every person has a "charm value". When a boy with charm value t1 and a girl with charm value t2 get together, their "8g value" is t1*t2. Every year the king will choose the Kth greatest number from all the N*M possible 8g values as the lucky number of the year. People on the island knows nothing but 8g, so they ask you to help them find the lucky number.

Input

The input contains multiply test cases(<= 10). Each test case contains three parts:

  1. 1 Three integers NM(1 <= N,M <= 100000) and K(1 <= K <= N*M) in a line, as mentioned above.

    N integers in a line, the charm value of each boy.

    M integers in a line, the charm value of each girl.

    All the charm values are integers between 1 and 100000(inclusive).

Process to the end-of-file.

Output

For each test case print a single line that contains the lucky number.

Sample Input

3 2 3
1 2 3
1 2

2 2 1
1 1
1 1

2 2 4
1 1
1 1

Sample Output

3
1
1


参考:http://blog.csdn.net/YZBYZZ/article/details/18455047?locationNum=10

题意:
两个数组,元素个数分别为n和m。两两相乘可得n*m个数,求第k大的数。

思路:
本渣是听了别人二分的想法后才写出的。
两数组皆 非升序 排序。

首先,二分枚举第k大的数可能是多少。
假设当前枚举到mid,则计算大于等于mid的数有多少个。设之为tmp个。
若tmp > k,说明 第k大的数比mid大
若tmp < k,说明 第k大的数比mid小
若tmp = k, 分两种情况:
若n*m个数中存在等于mid的,则mid为第k大的数
否则,第k大的数比mid大

其中,在找大于等于mid的数有多少个时,采用的是枚举第一个数组,二分第二个数组的方法。
同理,在找是否存在等于mid的数也是采用同样的方法。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
ll a[100005];
ll b[100005];
int n,m;
ll k;
bool cmp(const ll x,const ll y){return x>y;}
ll B_search_b(ll a,ll x)   //二分ai时对应b中结果大于等于x的元素个数 
{
	ll low=0,high=m-1;
	while(low<=high)
	{
		ll mid=(low+high)>>1;
		if(a*b[mid]<x)
			high=mid-1;
		else
			low=mid+1;
	}
	return low;
}
ll Selection_a(ll x)         //选择数为x时大于等于x的数的个数 
{
	ll sum=0;
	for(int i=0;i<n;i++)
	{
		sum+=B_search_b(a[i],x);
	}
	return sum;
}
bool find_in_b(ll a,ll x)
{
	ll low=0,high=m-1;
	while(low<=high)
	{
		ll mid=(low+high)>>1;
		if(a*b[mid]==x)return true;
		else if(a*b[mid]<x)
			high=mid-1;
		else
			low=mid+1;
	}
	return false;
}
bool find_x(ll x)
{
	for(int i=0;i<n;i++)
	{
		if(find_in_b(a[i],x))return true;
	}
	return false;
}
ll BinaryResearch(ll low,ll high)
{
	ll result=0;
	while(low<=high)
	{
		ll mid=(low+high)>>1;
		ll tmp=Selection_a(mid);
		if(tmp==k)
		{
			if(find_x(mid))
			{
				result=mid;
				break;
			}
			else low=mid+1;
		}
		else if(tmp>k)    //mid小于第k大的数 
		{
			low=mid+1;
			result=mid;
		}
		else 
			high=mid-1;
	}
	return result;
}
int main()
{
	while(~scanf("%d%d%lld",&n,&m,&k))
	{
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		for(int i=0;i<n;i++)scanf("%lld",&a[i]);
		for(int i=0;i<m;i++)scanf("%lld",&b[i]);
		sort(a,a+n,cmp);
		sort(b,b+m,cmp);
		printf("%lld\n",BinaryResearch(a[n-1]*b[m-1],a[0]*b[0]));
	}
}

数组一定要开成long long不然wa惨了。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值