1. 程式人生 > >noip模擬賽 第K小數

noip模擬賽 第K小數

pre 乘法 格式 color 行為 scan 從大到小 約定 num

【問題描述】
有兩個正整數數列,元素個數分別為N和M。從兩個數列中分別任取一個數
相乘,這樣一共可以得到N*M個數,詢問這N*M個數中第K小數是多少。
【輸入格式】
輸入文件名為number.in。
輸入文件包含三行。
第一行為三個正整數N,M和K。
第二行為N個正整數,表示第一個數列。
第三行為M個正整數,表述第二個數列。
【輸出格式】
輸出文件名為number.out。
輸出文件包含一行,一個正整數表示第K小數。
【輸入輸出樣例1】

number.in number.out
2 3 4
1 2
2 1 3
3


【輸入輸出樣例2】

number.in number.out
5 5 18
7 2 3 5 8
3 1 3 2 5
16


【數據規模與約定】

樣例點編號 N M K 元素大小(≤)
1 20 20 150 10^4
2 50 50 2000 10^4
3 100 80 5000 10^9
4 200 200 26000 10^9
5 10000 10000 50050000 10^4
6 1000 20000 9500000 10^4
7 1000 20000 10000500 10^9
8 2000 20000 190000 10^9
9 2000 20000 199000 10^9
10 20000 20000 210005000 10^4
11 20000 20000 210000 10^5
12 20000 20000 200000 10^9
13 20000
20000 220000500 10^5
14 20000 20000 199000500 10^9
15 200000 200000 180000 10^4
16 200000 200000 200000 10^9
17 2000 200000 100001500 10^9
18 200000 180000 19550000000 10^5
19 200000 200000 19900010000 10^9
20 200000 200000 20000010000 10^9


分析:非常經典的一道題,要求第K小/大之類的顯然可以二分,看比它小的數有多少個,統計個數主要還是乘法原理,將兩個序列排序,然後移動兩個指針,一個從小到大,一個從大到小,因為滿足單調性,一個乘法就解決了.


#include <cstdio>
#include <cstring>
#include 
<iostream> #include <algorithm> using namespace std; typedef long long ll; ll n, m, k, a[200010], b[200010], max1, max2, ans, cnt1, cnt2; ll check(ll x) { ll cur1 = 1, cur2 = m, sum = 0; while (cur2 > 0 && cur1 <= n) { while (a[cur1] * b[cur2] > x) cur2--; sum += cur2; cur1++; } return sum; } int main() { scanf("%lld%lld%lld", &n, &m, &k); for (ll i = 1; i <= n; i++) { scanf("%lld", &a[i]); max1 = max(max1, a[i]); } for (ll i = 1; i <= m; i++) { scanf("%lld", &b[i]); max2 = max(max2, b[i]); } sort(a + 1, a + 1 + n); sort(b + 1, b + 1 + m); ll l = 1, r = max1 * max2; while (l <= r) { ll mid = (l + r) >> 1; if (check(mid) >= k) { ans = mid; r = mid - 1; } else l = mid + 1; } printf("%lld\n", ans); return 0; }

noip模擬賽 第K小數