1. 程式人生 > >第k小數3

第k小數3

所有 -- 答案 下界 span [1] namespace 數組a div

給定兩個升序的整型數組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 }

第k小數3