ZOJ 3278 8G Island (二分套二分)

来源:互联网 发布:cc漫画软件下载 编辑:程序博客网 时间:2024/05/22 17:24

俗话说二分很难,真的很难,,,很难。(我会说这道题解一晚上么)

题目让求两数列乘积的n*m个数中第k大。

思路就是在[min,max]的范围内二分答案,然后对于每个二分的中点mid,枚举a[i],二分求出对于每个a[i],有几个b[j]使得a[i]*b[j]>=mid。然后把统计的个数全都加起来就是mid在n*m个数中的排名。

我们要找的就是最大的mid使得n*m个数中大于等于mid的数共有k个

#pragma warning(disable:4996)#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long LL;int n, m;LL k;int a[100005], b[100005];int find(int target, LL midd){//返回左数第一个b[i]使得b[i]*target>=midd的角标iint low = 1, high = m;while (low + 1 < high){int mid = (low + high) >> 1;if ((LL)b[mid] * target < midd)low = mid + 1;else high = mid;}if ((LL)b[low] * target >= midd)return low;if ((LL)b[high] * target >= midd)return high;return m + 1;}int main(){//freopen("in.txt", "r", stdin);while (~scanf("%d", &n)){scanf("%d %lld", &m, &k);for (int i = 1; i <= n; i++)scanf("%d", a + i);for (int j = 1; j <= m; j++)scanf("%d", b + j);sort(a + 1, a + 1 + n);sort(b + 1, b + 1 + m);LL low = (LL)a[1] * b[1], high = (LL)a[n] * b[m];while (low + 1< high){LL mid = (low + high) >> 1;LL rank = 0;for (int i = 1; i <= n; i++){int index = find(a[i], mid);rank += m + 1 - index;}//rank是n*m个数中>=mid的个数if (rank < k)high = mid - 1;else if (rank>k)low = mid + 1;else low = mid;}LL ans = -1;for (int i = 1; i <= n; i++){int u = find(a[i], low);int v = find(a[i], high);if (low%a[i] == 0 && u <= m&&b[u] * (LL)a[i] == low){ans = low;break;}if (high%a[i] == 0 && v <= m&&b[v] * (LL)a[i] == high){ans = high;break;}}printf("%lld\n", ans);}return 0;}


0 0
原创粉丝点击