zoukankan      html  css  js  c++  java
  • 【洛谷T7153】(考试) 中位数

    题目描述

    给定 n 个数 a1, a2, ..., an,求这 n 个数两两的差值(共 n(n−1)

    2 个)的中位数。

    输入格式:

    第一行一个正整数 n,表示数的个数。

    接下来一行 n 个正整数,分别为 a1, a2, ..., an。

    输出格式:

    一行一个数表示差值的中位数。

    输入输出样例

    输入样例#1:

    3
    4 2 6

    输出样例#1:

    2

    题解

    这里貌似没有数据范围。。。。
    好吧
    我补一下。。
    30%数据保证O(n^2)能出解
    100%数据n<=2000000,且结果是整数

    首先,我们来看看30大暴力
    依次求出所有的差(O(n^2))
    排序,求解

    但是,正解是啥?

    先提前剧透一下:二分

    我们每次二分出一个值(中位数)
    然后判断是否可行

    如何判断?首先对所有数进行一次排序
    接着,从当前数开始
    计算一下加上中位数后比它小的数的个数

    最后,统计一下加了几个数

    如果 大于/小于 了数字差的数量的一半 就想 小/大 的地方继续二分

    这样求完。。。发现,,还是有点问题。。
    的确,
    中位数要么是一个数列中的值,
    要么是两个数的平均值

    所以,要求出两个中位数并且计算它们的平均值即可。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define ll long long
    #define MAX 2000100
    ll n;
    ll a[MAX];
    ll tot;
    ll ans;
    inline int read()
    {
           register int x=0,t=1;
           register char ch=getchar();
           while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
           if(ch=='-'){t=-1;ch=getchar();}
           while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
           return x*t;
    }
    int main()
    {
           n=read();
           for(int i=1;i<=n;++i)
              a[i]=read();
           sort(&a[1],&a[n+1]);
           tot=(ll)(n-1)*n/2;
           ll L=0,R=a[n]-a[1];
           while(L<R)//二分找答案 
           {
                    ll mid=(L+R)>>1;
                    ll tt=0,pp=1;
                    for(int i=1;i<=n;++i)
                    {
                            while(a[pp]<=a[i]+mid&&pp<=n)++pp;
                            tt+=n-pp+1;
                    }
                    if(tt*2>tot)L=mid+1;
                    else        R=mid;
           }
           ans=R;
           L=0;R=a[n]-a[1];
           while(L<R)//中位数可能是两个的平均数,所以要二分两次 
           {
                    ll mid=(L+R)>>1;
                    ll tt=0,pp=1;
                    for(int i=1;i<=n;++i)
                    {
                            while(a[pp]<=a[i]+mid&&pp<=n)++pp;
                            tt+=n-pp+1;
                    }
                    if(tt*2>=tot)L=mid+1;
                    else        R=mid;
           }
           cout<<((ans+R)>>1)<<endl;
           return 0;
    }
    
  • 相关阅读:
    链表操作二——中间结点的删除等
    stack vector queue 等的实现方式<<0922
    任何和日期相关的函数都在这里<<0922
    类函数返回该类的问题<<0922
    Android学习笔记之PullToRefreshListView和BaseAdapter的使用
    记录Android学习过程中遇到的问题
    ruby appium 准备环境
    os x升级到10.10后appium不能测试通过的解决办法
    appium 在ios模拟器上面成功运行
    appium IOS真机测试
  • 原文地址:https://www.cnblogs.com/cjyyb/p/7197257.html
Copyright © 2011-2022 走看看