给定两个升序的整型数组A和B。将A和B中的元素两辆相加可以得到数组C,现在给你数组A和B,求由数组A和B两辆相加得到的数组C中,第k小的数字时多少。
采用二分的方法
显然答案在【a[1] + b[1],a[n] + b[m]】的区间,即下界为a[1] + b[1], 上界为a[n] + b[m],反复枚举上下界的中间值mid与k比较以缩小范围即可找到答案。
假设a[] = 【1,2, 3, 4, 5】,b[] = 【6,7,8,9,10】,mid = a[1] + b[1] = 7, max = a[5] + b[5] = 15, mid = (min + max) / 2 = 11。
从a[1]到a[m],一次逆序与b数组的元素相加,若某一轮中a[i] 加到b[j]时两数和不大于k,则该轮中比k值小的元素的个数为j。
下一轮a[i + 1]与b数组逆序相加时,直接从b[j]开始加即可,因为很显然的,a[i + 1] > a[i]。
累加所有比k值小的元素个数即为mid在两数组中的排序数。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 typedef long long LL; 7 LL A[100000], B[100000]; 8 9 int compare(const void *p, const void *q)//函数指针 10 /*在这句话里 p,q肯定是一个指针变量 11 (int *)p是表示把p强制转换成一个int型的指针。 12 如果以前p是char型,编译器会认为p指向的那一个字节的内存单元是p里面的东西 13 把a转换成int型,编译器会认为a指向的连续四个字节里的东西都是p里面的。 14 *(int *)p就是取p指向的内容的意思,跟*p的那个*作用一样*/ 15 { 16 return *(LL *)p - *(LL *)q; 17 } 18 19 LL cal(LL A[], LL m, LL B[], LL n, LL mid)//计算mid值在两数组中的排序数 20 { 21 LL i, j; 22 LL cnt = 0; 23 j = n - 1; 24 for(i = 0; i < m; ++i) 25 { 26 while(j >= 0 && A[i] + B[j] > mid)//定位B数组中相加比mid小的位置 27 --j; //累计 28 cnt += (j + 1); 29 } 30 return cnt; 31 } 32 LL findKth(LL A[], LL m, LL B[], LL n, LL k) 33 { 34 LL min = A[0] + B[0]; 35 LL max = A[m - 1] + B[n - 1]; 36 LL mid; 37 LL ans; 38 39 while(min <= max) 40 { 41 mid = ((max - min) >> 1) + min; 42 if(k <= cal(A, m, B, n, mid)) 43 max = mid - 1; 44 else 45 min = mid + 1; 46 } 47 } 48 49 int main() 50 { 51 LL m, n, k, i; 52 while(scanf("%lld%lld%lld", &m, &n, &k) != EOF) 53 { 54 for(i = 0; i < m; ++i) 55 cin >> A[i]; 56 for(i = 0; i < n; ++i) 57 cin >> B[i]; 58 qsort(A, m, sizeof(LL), compare); 59 qsort(B, n, sizeof(LL), compare); 60 cout << findKth(A, m, B, n, k); 61 } 62 return 0; 63 }
将cal函数也采用二分查找的方式计算小于等于k的数字个数
1 #include<cstdio> 2 #include<iostream> 3 #include<cstdlib> 4 #include<algorithm> 5 using namespace std; 6 7 long long a[109999]; 8 long long b[109999]; 9 long long n, m; 10 11 12 long long cmp(long long a, long long b) 13 { 14 return a < b; 15 } 16 17 long long cal(long long v) 18 { 19 long long ll, rr, mid, i, add = 0; 20 long long min, max; 21 for(i = 1; i <= n; i++) 22 { 23 min = a[i] + b[1]; 24 max = a[i] + b[m]; 25 if(v < min) 26 break; 27 if(v >= max) 28 { 29 add += m; 30 continue; 31 } 32 ll = 1; 33 rr = m; 34 while(ll <= rr) 35 { 36 mid = (ll + rr) / 2; 37 if(v < (a[i] + b[mid])) 38 rr = mid - 1; 39 else 40 ll = mid + 1; 41 } 42 if(v != (a[i] + b[ll])) 43 ll--; 44 add += ll; 45 } 46 return mid; 47 } 48 49 long long find(long long ll, long long rr, long long k) 50 { 51 long long mid, i; 52 while(ll <= rr) 53 { 54 mid = (ll + rr) / 2; 55 if(k < cal(mid)) 56 rr = mid - 1; 57 else 58 ll = mid + 1; 59 } 60 return ll; 61 } 62 63 int main() 64 { 65 long long k, ll, rr; 66 while(scanf("%ld%ld%ld", &n, &m, &k) != EOF) 67 { 68 long long i; 69 for(i = 1; i <= n; i++) 70 cin >> a[i]; 71 for(i = 1; i <= m; i++) 72 cin >> b[i]; 73 sort(&a[1], &a[n + 1], cmp); 74 sort(&b[1], &b[1 + m], cmp); 75 76 ll = a[1] + b[1]; 77 rr = a[n] + b[m]; 78 79 cout << find(ll, rr, k) << endl; 80 } 81 return 0; 82 }