• 查找第K大的值


    这种题一般是给定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

    代码如下:

     1 int N;
     2 int a[MAXN];
     3 LL M;
     4 
     5 bool C(int t) {
     6     LL cnt = 0;
     7     for (int i = 0; i < N; i++) {
     8         cnt += N - (lower_bound(a + i + 1, a + N, a[i] + t) - a);
     9     }
    10     return cnt <= M / 2;
    11 }
    12 
    13 void solve() {
    14     sort(a, a + N);
    15     M = N * (N - 1) / 2;
    16     int ub = a[N - 1] + 1, lb = 0;
    17     while (ub - lb > 1) {
    18         int mid = (ub + lb) >> 1;
    19         if (C(mid)) {
    20             ub = mid;
    21         } else {
    22             lb = mid;
    23         }
    24     }
    25     cout << lb << endl;
    26     return;
    27 }
    28 
    29 int main() {
    30 #ifndef ONLINE_JUDGE
    31     freopen("input.txt", "r", stdin);
    32 #endif  // !ONLINE_JUDGE
    33     while (~scanf("%d", &N)) {
    34         for (int i = 0; i < N; i++) {
    35             scanf("%d", &a[i]);
    36         }
    37         solve();
    38     }
    39     return 0;
    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$ 值的大小关系。

    代码如下:

     1 LL N, M;
     2 
     3 LL cal(LL i, LL j) { return i * i + 100000 * i + j * j - 100000 * j + i * j; }
     4 
     5 bool C(LL x) {
     6     LL sum = 0;
     7     for (int j = 1; j <= N; j++) {
     8         LL ub = N + 1, lb = 0;
     9         LL ans = 0;
    10         while (ub - lb > 1) {
    11             LL mid = (ub + lb) >> 1;
    12             if (cal(mid, j) <= x) {
    13                 ans = mid;
    14                 lb = mid;
    15             } else {
    16                 ub = mid;
    17             }
    18         }
    19         sum += ans;
    20     }
    21     return sum >= M;
    22 }
    23 
    24 void solve() {
    25     LL ub = LLINF, lb = -LLINF;
    26     while (ub - lb > 1) {
    27         LL mid = (ub + lb) >> 1;
    28         if (C(mid)) {
    29             ub = mid;
    30         } else {
    31             lb = mid;
    32         }
    33     }
    34     cout << ub << endl;
    35     return;
    36 }
    37 
    38 int main() {
    39 #ifndef ONLINE_JUDGE
    40     freopen("input.txt", "r", stdin);
    41 #endif  // !ONLINE_JUDGE
    42     int T = READ();
    43     while (T--) {
    44         getchar();
    45         scanf("%lld%lld", &N, &M);
    46         solve();
    47     }
    48     return 0;
    49 }
  • 相关阅读:
    2017 湖南省赛 K Football Training Camp
    一些相似单词的区别之处
    LeetCode301. Remove Invalid Parentheses
    算法刷题细节点总结
    LeetCode765. Couples Holding Hands
    LeetCode741. Cherry Pickup
    LeetCode312. Burst Balloons
    LeetCode679. 24 Game
    LeetCode862. Shortest Subarray with Sum at Least K
    LeetCode818. Race Car
  • 原文地址:https://www.cnblogs.com/romaLzhih/p/12342492.html
Copyright © 2020-2023  润新知