zoukankan      html  css  js  c++  java
  • codeforces 166C Median

    C. Median
    time limit per test
    2 seconds
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    median in an array with the length of n is an element which occupies position number  after we sort the elements in the non-decreasing order (the array elements are numbered starting with 1). A median of an array (2, 6, 1, 2, 3) is the number 2, and a median of array (0, 96, 17, 23) — the number 17.

    We define an expression  as the integer part of dividing number a by number b.

    One day Vasya showed Petya an array consisting of n integers and suggested finding the array's median. Petya didn't even look at the array and said that it equals x. Petya is a very honest boy, so he decided to add several numbers to the given array so that the median of the resulting array would be equal to x.

    Petya can add any integers from 1 to 105 to the array, including the same numbers. Of course, he can add nothing to the array. If a number is added multiple times, then we should consider it the number of times it occurs. It is not allowed to delete of change initial numbers of the array.

    While Petya is busy distracting Vasya, your task is to find the minimum number of elements he will need.

    Input

    The first input line contains two space-separated integers n and x (1 ≤ n ≤ 5001 ≤ x ≤ 105) — the initial array's length and the required median's value. The second line contains n space-separated numbers — the initial array. The elements of the array are integers from 1 to 105. The array elements are not necessarily different.

    Output

    Print the only integer — the minimum number of elements Petya needs to add to the array so that its median equals x.

            题目大意:给你一个数n 和一个数k,然后给你一个由n个数组成的数列,先按非递减序排好,然后让你判断这个数列的第 (n + 1) / 2  项是不是k(数列的下标从1开始),如果不是,你要往这个数列中插入m个数使插入后的数列的第(n + m + 1) /  2 项是k , 输出m的最小值。 

             解题思路:先判断数k是否在原数列中,没有的话就把数k加入数列,然后原始数列排序,接着找出数k在数列中第一次 first 和最后一次出现的位置second,同时算出 t  =(n + 1)/ 2  ,如果 t >= first && t <= second , 就直接输出结果;如果  t  <  first ,则需要在数k的后面添加    大于或等于 k    的数 ;如果 t  > second , 则需要在数k的前面     小于或等于 k      的数。

             Ps: 此题用暴力法可能会TLE, 我用的是二分法,只是其中有许多细节需要注意。具体请看代码:

     

    #include<iostream>
    #include<cstring>
    #include<string>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    using namespace std ;
    const int MAXN = 1e5 + 5 ;
    int vis[MAXN] ;
    int s[MAXN] ;
    bool cmp(int a , int b)
    {
        return a < b ;
    }
    int main()
    {
        int n , k ;
        while (scanf("%d%d" , &n , &k) != EOF)
        {
            int i ;
            int ans = 0 ;
            memset(vis , 0 , sizeof(vis)) ;
            for(i = 1 ; i <= n ; i ++)
            {
                scanf("%d" , &s[i]) ;
                vis[s[i]] ++ ;
            }
            if(vis[k] == 0)  // 如果数列中没有k,则加入k
            {
                vis[k] ++ ;
                n ++ ;
                s[n] = k ;
                ans ++ ;
            }
            sort(s + 1, s + n + 1, cmp) ; // 因为数列的下标是从1 开始的,
                                          //所以要把 1 ~ n 项排序
            int t = (n + 1) >> 1 ;
            int first = -1 ;
            int second = -1 ;
            int j ;
            for(j = 1 ; j <= n ; j ++) // 记录 k 第一次出现的位置和最后一次出现的位置
            {
                if(k == s[j])
                {
                    if(first == -1)
                    first = j ;
                    second = j ;
                }
            }
            if(t >= first && t <= second)
            {
                printf("%d
    " , ans) ;
            }
            // 以下是二分过程,是此程序的精华,请仔细理解
            else if( t < first)
            {
                int r = n , l = 1 , mid ;
                while(r > l + 1)    // 注意跳出条件
                {
                    mid = (r + l) >> 1 ;
                    int tmp = (mid + n + 1) >> 1 ;
                    if(first < tmp )
                    {
                        r = mid - 1 ;
                    }
                    else if(first > tmp)
                    {
                        l = mid ;
                    }
                    else        // 注意相等的情况也要单独判断
                    {
                        r = mid ;
                    }
                }
                if(r == l + 1)  // 此处也是必不可少的 !!
                {
                    if((l + n + 1) >> 1 == first)
                    {
                        ans += l ;
                    }
                    else
                    ans += r ;
                }
                else
                ans += r ;
                printf("%d
    " , ans) ;
            }
            // 以下过程道理同上
            else
            {
                int r = n , l = 1 , mid ;
                while (r > l + 1)
                {
                    mid = (r + l) >> 1 ;
                    int tmp = (n + mid + 1) >> 1 ;
                    if(second + mid < tmp)
                    {
                        l = mid + 1;
                    }
                    else if(second + mid == tmp)
                    {
                        r = mid ;
                    }
                    else
                    {
                        r = mid - 1 ;
                    }
                }
                if(r == l + 1)
                {
                    if((l + n + 1) >> 1 == second + l)
                    {
                        ans += l ;
                    }
                    else
                    ans += r ;
                }
                else
                ans += r ;
                printf("%d" , ans) ;
            }
        }
        return 0 ;
    }
    
    
    
    
    
    
    
    


  • 相关阅读:
    波场TRX 钱包开发,看这篇就够了
    比特币(BTC)钱包对接之如何实现平台用户注册地址生成?
    如何搭建泰达币(USDT)钱包节点?
    交易所如何对接狗狗币(DOGE)钱包?这点不可忽视
    【转】影响加密数字货币交易情绪有哪些?如何控制?
    探寻DOT充提币接口对接流程
    你需要PCIE×4硬盘
    安装rename perl version
    Emacs-log
    Biopython Numpy 安装问题
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3221529.html
Copyright © 2011-2022 走看看