BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / acm-icpc / #94526同步于 2017/11/28
该镜像源已超过 30 天没有更新,可能在源站已被删除。
ACM_ICPC机器人发帖

两个已排序好的序列分别相乘,然后排序

bdyzhy9527
2017/11/28镜像同步13 回复
有两个长度是5000的数组,已经排序好,数据分布大概是这样的: 基本上是数据的范围在[0.5, 3.5]之间,现在将两个序列的每个元素分别相乘,生成一个矩阵,然后用一种方法选500个index,要求这500个index要尽可能的和最大的前500个index重合。 做实验的时候遇到的问题,已经想了很长时间了,也没有一个有效的办法[ema1] 跪求大神指导[ema11]
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
wr445566机器人#1 · 2017/12/1
直接选最大的500个用优先级队列就可以做到nlog(n)级别吧
unimit机器人#2 · 2017/12/1
楼上肯定是不行的,n=5000*5000,计算量太大。 首先,把两个数组从小到大排列(纯粹因为习惯),我直观的感觉是首先array1[i<(5000-23) ×array2[j<(5000-23)]这部分数据首先可以排除掉,剩下23*5000*2-23*23大概20万数据,要利用数据线性(或者近似线性)的部分再把一部分数据pass掉。 如果再想想,array1和array2成线性的话,array1 ×array2就会形成一个离散的双曲抛物面zij(xi,yj)=xiyj。怎样求一个离散的马鞍面最大的k个zij? i、j最后组成的集合将是被ij=C(k)这条双曲线围住的部分。使C'(k)=C*array1[5000-23]*array2[5000-23],(C为常数),把这个曲线外的i,k排除掉。 这还没完,因为还有两个非线性部分相乘的区域同样被排除了,而这两个部分有可能存在top500的元素。想想就很复杂,生成5000*5000矩阵按行列在三维画图的话应该是一个边缘畸变的离散双曲抛物面,在这样一个畸变的曲面求topk,学渣的我感觉数学已经完全不够用了。
unimit机器人#3 · 2017/12/1
如果精确度可以放宽,可以考虑采样,将两个数组采样成为500*500=250000,求top500,先排除(500-23)*(500-23)个数据,剩余23*500*2-23*23大概2万数据,做堆排或者部分快排,得到500点,每个点增加周围八个点,共计4500点,再取500点再排,重复直到500个点收敛。简单粗暴,效果看运气,速度靠人品。 我猜想最后ij集合应该是一个边界处发生畸变的双曲线围成的图形。 从你的数据来看,中间部分基本是线性的,只是前后有畸变,这个问题有点像通信信号里面在边界处产生的噪声,而要求信号里topK个主分量,或许看看信号处理的书也许有好的解决思路。
bdyzhy9527机器人#4 · 2017/12/1
哇,十分感谢,今天没怎么看论坛回复晚了,我认真看看[ema11] 【 在 unimit 的大作中提到: 】 : 如果精确度可以放宽,可以考虑采样,将两个数组采样成为500*500=250000,求top500,先排除(500-23)*(500-23)个数据,剩余23*500*2-23*23大概2万数据,做堆排或者部分快排,得到500点,每个点增加周围八个点,共计4500点,再取500点再排,重复直到500个点收敛。简单粗暴,效果看运气,速度靠人品。 : 我猜想最后ij集合应该是一个边界处发生畸变的双曲线围成的图形。 : 从你的数据来看,中间部分基本是线性的,只是前后有畸变,这个问题有点像通信信号里面在边界处产生的噪声,而要求信号里topK个主分量,或许看看信号处理的书也许有好的解决思路。
unimit机器人#5 · 2017/12/1
不客气。这个问题很有意思,有没有结果都可以继续讨论。 【 在 bdyzhy9527 的大作中提到: 】 : 哇,十分感谢,今天没怎么看论坛回复晚了,我认真看看
hiyot机器人#6 · 2017/12/3
不想打字.. 贴段代码吧, 楼主要是看完还有兴趣可以ping我 vector<int> bigest_n(vector<int> a, vector<int> b, int cnt) { int l = a[0] * b[0]; int u = a.back() * b.back() + 1; while (l + 1 != u) { int m = (l + u) / 2; int not_less_than_m = 0; for (int ai = 0, bi = b.size() - 1; ai < a.size(); ai++) { while (bi >= 0 && a[ai] * b[bi] >= m) { bi--; } not_less_than_m += b.size() - 1 - bi; } if (not_less_than_m >= cnt) { l = m; } else { u = m; } } vector<int> ans; for (int i = 0; i < a.size(); i++) { for (int j = b.size() - 1; j >= 0; j--) { if (a[i] * b[j] > l) { ans.push_back(a[i] * b[j]); } } } while (ans.size() < cnt) ans.push_back(l); sort(ans.begin(), ans.end()); return ans; }
moyuji机器人#7 · 2017/12/4
相乘取对数就是加法,两个log数组merge sort然后从右端不端添加,直到取到的数子个数m*n >500
unimit机器人#8 · 2017/12/5
m和n指的是? 【 在 moyuji 的大作中提到: 】 : 相乘取对数就是加法,两个log数组merge sort然后从右端不端添加,直到取到的数子个数m*n >500
unimit机器人#9 · 2017/12/5
你好,为什么要加1,能不能简单描述一下算法 【 在 hiyot 的大作中提到: 】 : 不想打字.. 贴段代码吧, 楼主要是看完还有兴趣可以ping我 : [code=c] : vector<int> bigest_n(vector<int> a, vector<int> b, int cnt) { : ...................