這種題一般是給定n個數,然後n個數之間通過某種計算得到了新的數列,求這新的數列的第k大的值
poj3579
題意:用$n$個數的序列$x[i]$,生成乙個新序列$b$。
新的序列定義為:對於任意的$ i$,$j$且 $i != j $有$b = abs(x[i] - x[j])$
問新序列的中位數是什麼,如果新序列的長度為偶數那麼我們定義中位數為排序後第len/2位置的那個數
解法:相當於問新序列中的第k大的數多少。
注意新數列不可能全都算出來。
二分答案,二分那個第k大的數的值。
$x[i]-x[j] \ge mid$
相當於$x[i] \ge mid+x[j]$
然後我們在排序過的原陣列中,對每個$a[i]$二分這個$mid$值,統計有多少個值小於它,統計累加所有的值,最後看是不是小於k
**如下:
1intn;
2int
a[maxn];
3ll m;45
bool c(int
t) 10
return cnt <= m / 2;11
}1213void
solve() else24}
25 cout << lb <26return;27
}2829int
main()
37solve();38}
39return0;
40 }
poj3685
題意:有乙個$ n*n$ 的矩陣$ a$ ,$a[i][j]=i^2+100000i+j^2-100000j+ij$
求所有矩陣元素中第$ k$ 大的值
解法:求第$ k$ 大的值,二分答案
首先肯定是二分這個k值是多少,接下來就是驗證的問題。
由於$ n*n$ 的值很大,所以我們必須找到它的單調性,那麼有以下式子:
$a[i+1][j] = a[i][j] + (2*i + j + 1 + 100000)$(同一列遞推式)
$a[i][j+1] = a[i][j] + (2*j + i + 1 - 100000)$ (同一行遞推式)
可以發現:在列方向上,矩陣單調遞增,而在行方向上上,當$ (2*j + i + 1)> 100000 $ 時,遞增,反之遞減。
那麼我們在每個列方向上直接二分那個$ i$ 值的大小,判斷的一句就是$ a[i][j]$ 與假想$ k$ 值的大小關係。
**如下:
1ll n, m;
23 ll cal(ll i, ll j) 45
bool
c(ll x) else18}
19 sum +=ans;20}
21return sum >=m;22}
2324
void
solve() else33}
34 cout << ub <35return;36
}3738int
main()
48return0;
49 }
演算法實踐系列 查詢第K大值
下面的演算法實現基於隨機化快排,有乙個前提是需要假設所有的元素都不相等,否則演算法不成立。下面是具體實現 1 隨機劃分演算法與快排一樣 快速排序的分隔,即 對於乙個指定的主元x,找到位置i,使得i的左邊元素都小於等於x,右邊都大於等於x.private int quicksortpartion in...
演算法實踐系列 查詢第K大值
下面的演算法實現基於隨機化快排,有乙個前提是需要假設所有的元素都不相等,否則演算法不成立。下面是具體實現 1 隨機劃分演算法與快排一樣 快速排序的分隔,即 對於乙個指定的主元x,找到位置i,使得i的左邊元素都小於等於x,右邊都大於等於x.private int quicksortpartion in...
作業 查詢第k大的元素
由於是要找 k 個最大的數,所以沒有必要對所有數進行完整的排序。每次只保留 k 個當前最大的數就可以,然後每次對新來的元素跟當前 k 個樹中最小的數比較,新元素大的話則插入到陣列中,否則跳過。迴圈結束後陣列中最小的數即是我們要找到第 k 大的數。時間複雜度 n k logk 注意 巢狀for迴圈裡面...