Kth Largest

pmars 2009-11-29 09:23:18
最近碰到了一道acm题:
http://acm.hrbeu.edu.cn/index.php?act=problem&proid=5012&cid=0

题目描述很简单:
两个数组A和B,a为A的元素,b为B的元素,定义c=a*b,求第K大的c!其中0<a,b<10000

大家帮我想一下又什么好的算法没有!一般的方法我试过了,超时啊!
...全文
465 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
whg01 2009-11-29
  • 打赏
  • 举报
回复
你都试过什么方法?
do_fork 2009-11-29
  • 打赏
  • 举报
回复
这道题不能把所有的C都计算出来,那样做肯定超时。
二维第K大数问题,用二分法应该也能有效降低计算规模。


先把A和B的序列分别从小到大排序,
将A分为两个部分,分别是Ax, Ay,长度分别为lax, lay
将B分为两个部分,分别是Bx, By, 长度分别为lbx, lby

1. 若 K <= lay*lby,则第K大数一定在Ay*By中,
2. 若 K > lay*lby + lay*lbx + lax*lby, 则第K大数一定在Ax*Bx中,
3. 其余情况,第K大数一定在 Ax*By 或者 Bx*Ay 中。

将问题规模减小,得到一个划分,
Ax, Ay, Az
Bx, By, Bz
使得第K大数不可能出现在 Ax*Bx 中,也不可能出现在Az*Bz中,
并且它一定出现在 Ay*By 中
pmars 2009-11-29
  • 打赏
  • 举报
回复
好强!
honghu069 2009-11-29
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 pmars 的回复:]
好厉害,真的过了,只用了一个小时的时间呢!恩,我就是有点看不懂啊,怎么个想法啊?
我还得好好看看,吸收一下,学到了!!
[/Quote]
他的思想应该是先算出最大和最小的数,而第K大的数在这两者之间,而且符合单调性,可以二分答案
对于二分出的这个数,进行验证
pmars 2009-11-29
  • 打赏
  • 举报
回复
好厉害,真的过了,只用了一个小时的时间呢!恩,我就是有点看不懂啊,怎么个想法啊?
我还得好好看看,吸收一下,学到了!!
baihacker 2009-11-29
  • 打赏
  • 举报
回复

//这是对偶的写法
#include <iostream>
#include <deque>
#include <vector>
#include <functional>
#include <algorithm>
#include <cstdio>
using namespace std;

int data1[10005], data2[10005];
int main(void)
{
int n, m;
int result = 0;
int cas;scanf("%d", &cas);
while (cas--)
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; ++i) scanf("%d", data1+i);
for (int i = 0; i < n; ++i) scanf("%d", data2+i);
int curr = 0;
sort(data1, data1+n);
sort(data2, data2+n);
int l = data1[0] * data2[0], r = data1[n-1] * data2[n-1];
while (l <= r)
{
int mid = (l + r) >> 1;
int gt = 0;
for (int i = 0; i < n; ++i)
{
int a = 0, b = n - 1;
while (a <= b)
{
int c = (a + b) >> 1;
int t = data1[i] * data2[c];
if (t < mid) a = c + 1;
else b = c - 1;
}
gt += n - a;
if (gt >= m) break;
}
if (gt >= m) l = mid + 1;
else r = mid - 1;
}
printf("%d\n", r);
}
return 0;
}
baihacker 2009-11-29
  • 打赏
  • 举报
回复
你可以用二分算法处理这个问题:
#include <iostream>
#include <deque>
#include <vector>
#include <functional>
#include <algorithm>
#include <cstdio>
using namespace std;

int data1[10005], data2[10005];
int main(void)
{
int n, m;
int result = 0;
int cas;scanf("%d", &cas);
while (cas--)
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; ++i) scanf("%d", data1+i);
for (int i = 0; i < n; ++i) scanf("%d", data2+i);
int curr = 0;
sort(data1, data1+n);
sort(data2, data2+n);
int l = data1[0] * data2[0], r = data1[n-1] * data2[n-1];

m = n * n - m + 1;
while (l <= r)
{
int mid = (l + r) >> 1;
int lt = 0;
for (int i = 0; i < n; ++i)
{
int a = 0, b = n - 1;
while (a <= b)
{
int c = (a + b) >> 1;
int t = data1[i] * data2[c];
if (t > mid) b = c - 1;
else a = c + 1;
}
lt += a;
if (lt > m) break;
}
if (lt >= m) r = mid - 1;
else l = mid + 1;
}
printf("%d\n", l);
}
return 0;
}
pmars 2009-11-29
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 whg01 的回复:]
利用杨氏矩阵的特点,好像没有很快的方法。

[/Quote]

能具体说说么?
yangx19882 2009-11-29
  • 打赏
  • 举报
回复
没学过,看下
whg01 2009-11-29
  • 打赏
  • 举报
回复
利用杨氏矩阵的特点,好像没有很快的方法。
do_fork 2009-11-29
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 pmars 的回复:]
如上  lax= 2 , lay=2 ; lbx=2 , lby = 2 ;
之后A= {2,3,4,5}  B={1,2,5,7}

结果第四的应该是  35  28  25  21  20  这个呢?
[/Quote]

果真有问题,我再想想
pmars 2009-11-29
  • 打赏
  • 举报
回复
如上 lax= 2 , lay=2 ; lbx=2 , lby = 2 ;
之后A= {2,3,4,5} B={1,2,5,7}

结果第四的应该是 35 28 25 21 20 这个呢?
do_fork 2009-11-29
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 pmars 的回复:]
对于一楼的方法,我找了一个例子:
比如A={2, 3, 4, 5 }, B = {1 , 2, 3 , 6} ;
如果想找到第4大的c的话,给结果脑算一下:从大到小为:30,24,18,15,12,10.。。。。
之后取Ax={2,3},Ay= {4,5}, Bx={1,2} , By= {3,6};
这时lax=2,lay=2,lbx=2,lby=2;
因为K= 4 <=lay*lby, 所以像你说的:第K大数一定在Ay*By中, 可是这个例子不是这样啊~~~

可能我还不理解吧,请仔细给小弟讲讲啊~~~
[/Quote]

Ay={4,5},By={3,6}, 第4大数是15,Ay[1]*By[0]=5*3=15, 怎么不在Ay*By里了?
pmars 2009-11-29
  • 打赏
  • 举报
回复
对于一楼的方法,我找了一个例子:
比如A={2, 3, 4, 5 }, B = {1 , 2, 3 , 6} ;
如果想找到第4大的c的话,给结果脑算一下:从大到小为:30,24,18,15,12,10.。。。。
之后取Ax={2,3},Ay= {4,5}, Bx={1,2} , By= {3,6};
这时lax=2,lay=2,lbx=2,lby=2;
因为K= 4 <=lay*lby, 所以像你说的:第K大数一定在Ay*By中, 可是这个例子不是这样啊~~~

可能我还不理解吧,请仔细给小弟讲讲啊~~~
pmars 2009-11-29
  • 打赏
  • 举报
回复
对于二楼的问题:
首先将结果全部算出来肯定会超时,所以,我就利用了两个数组,一个存相乘的结果,一个存位置
A数组我给他排序了,B数组没有排
就是说result数组存结果,place数组存位置,初始化为n-1,这样查找一遍result数组就知道最大的了,将该位置的(假设第i个位置result结果最大)place[i]++,这样result[place]=A[place[i]]*B[i],这样每次都查找n遍,也就是说有K*n次就可以了,结果还是超时了!


对于一楼的解决方案:
好像真的挺好的,不过,问题所在就是,我没有太理解,恩,可以在说的明白点么?对不起,小弟是新手~~~

64,645

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧