题意:

给定N个初始值为0的数, 然后给定K个区间修改(区间[l,r] 每个元素加一), 求修改后序列的中位数。

分析:

K个离线的区间修改可以使用差分数组(http://www.cnblogs.com/Jadon97/p/8053946.html)实现。

关于对一个无序的序列找出中位数

方法一:

第一时间想到的方法是快排然后之间取中位数, 排序复杂度为O(NlogN),取第k大的数复杂度O(1)。

用时:124ms

#include <bits/stdc++.h>
using namespace std;
const int maxn = + ;
int N, K;
int a[maxn], d[maxn];
int main(){
cin >> N >> K;
d[] = a[];
for(int i = ; i < K; i++){
int a, b;
cin >> a >> b;
d[a]++, d[b+]--;
}
for(int i = ; i <= N; i++){
a[i] = a[i-] + d[i];
}
sort(a+,a++N);
cout << a[N/+] << "\n";
return ;
}

快排

方法二:

但其实还有有一个O(n)的算法,是利用快排的思想,详情可查看partiton算法http://blog.jobbole.com/105219/),这个算法可以延伸到求第k大的数

  • pos == k,则找到第 K 小的值,arr[pos];
  • pos > k,则第 K 小的值在左边部分的数组。
  • pos < k,则第 K 大的值在右边部分的数组。

而在最好情况下,每次将数组均分为长度相同的两半,运行时间 T(N) = N + T(N/2),时间复杂度是 O(N), 但是这个算法最坏情况是O(N²),暂时没想到很好的优化方法。

#include<bits/stdc++.h>
using namespace std;
const int maxn = + ;
int N, K;
int a[maxn], d[maxn];
int partition(int begin, int end) //[begin,end]左闭右闭区域
{
int pivot = a[begin];//选取第一个数为枢轴
while(begin < end)
{
while(begin < end && a[end] >= pivot) end--; //在后面选取一个小于枢轴的数
a[begin] = a[end]; //将那个数放到前面
while(begin < end && a[begin] <= pivot) begin++; //在前面选取一个大于枢轴的数
a[end] = a[begin];//将那个数放到后面
}
a[begin] = pivot;//最后将枢轴放回
return begin;//返回枢轴的下标
} int find_kth_number(int k){
int begin = , end = N;
int target_num = ;
while (begin <= end){
int pos = partition(begin, end);//查看枢轴的位置
if(pos == k){//如果枢轴 == k, 那么枢轴就是第k小的数
target_num = a[pos];
break;
}
else if(pos > k){//否则从左边找
end = pos - ;
}
else{//否则从右边找
begin = pos + ;
}
}
return target_num;
}
int main(){
scanf("%d %d", &N, &K);
d[] = a[];
for(int i = ; i < K; i++){
int a, b;
scanf("%d %d", &a, &b);
d[a]++, d[b+]--;
}
for(int i = ; i <= N; i++){
a[i] = a[i-] + d[i];
}
printf("%d\n", find_kth_number(N/+));
return ;
}

parition算法

但是有一个STL库函数eth_element(http://zh.cppreference.com/w/cpp/algorithm/nth_element), 思想应该是差不多的, 但因为优化原因运行时间可以过这题, 所以可以使用这个库函数快速求出第k大的数。

用时:74ms

#include <bits/stdc++.h>
using namespace std;
const int maxn = + ;
int N, K;
int a[maxn], d[maxn];
int main(){
scanf("%d %d", &N, &K);
d[] = a[];
for(int i = ; i < K; i++){
int a, b;
scanf("%d %d", &a, &b);
d[a]++, d[b+]--;
}
for(int i = ; i <= N; i++){
a[i] = a[i-] + d[i];
}
nth_element(a+,a+N/+,a++N);
printf("%d\n", a[N/+]);
return ;
}

nth_element

方法三:

对于这题特殊的区间修改, 因为N多达1e6, 而K只有25000, 所以最大的数也只有K, 所以我们求出区间修改的值的时候,可以把每个数的出现次数记录下来, 然后循环K次,把出现次数累计起来。加上某个数累计次数大于等于N/2时, 那个数就是中位数,复杂度是(N+K),应该是最快的方法了。

用时:49ms

 #include <bits/stdc++.h>
using namespace std;
const int maxn = ;
int N, K;
int a[maxn], d[maxn];
int cnt_num[ + ];
int main(){
scanf("%d %d", &N, &K);
d[] = a[];
for(int i = ; i < K; i++){
int a, b;
scanf("%d %d", &a, &b);
d[a]++, d[b+]--;
}
for(int i = ; i <= N; i++){
a[i] = a[i-] + d[i];
cnt_num[a[i]]++;//统计每个数字出现了多少次
}
int sum = , mid_num;
for(mid_num = ; mid_num <= K; mid_num++){
sum += cnt_num[mid_num];
if(sum > N/) break;
}
printf("%d\n", mid_num);
return ;
}

统计数字

Haybale Stacking(差分数组 + 求中位数的一些方法 + nth_element)的更多相关文章

  1. 三个数组求中位数,以及中位数的中位数----java算法实现

    求三个数组的中位数,以及中位数的中位数.   import java.util.Arrays; public class median { public static void main(String ...

  2. 1005E1 Median on Segments (Permutations Edition) 【思维+无序数组求中位数】

    题目:戳这里 百度之星初赛原题:戳这里 题意:n个不同的数,求中位数为m的区间有多少个. 解题思路: 此题的中位数就是个数为奇数的数组中,小于m的数和大于m的数一样多,个数为偶数的数组中,小于m的数比 ...

  3. 两个有序数组求中位数log(m+n)复杂度

    leetcode 第4题 中位数技巧: 对于长度为L的有序数组,它的中位数是(a[ceil((L+1)/2)]+a[floor((L+1)/2)])/2 算法原理: 类似三分法求极值 两个人都前进,谁 ...

  4. LeetCode第[4]题(Java):Median of Two Sorted Arrays (俩已排序数组求中位数)——HARD

    题目难度:hard There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median ...

  5. 三个数组求中位数,并且求最后中位数的中位数-----C++算法实现

    文件Median.h #include <list> class CMedian { public: explicit CMedian(); virtual ~CMedian(); voi ...

  6. [nowCoder] 两个不等长数组求第K大数

    给定两个有序数组arr1和arr2,在给定一个整数k,返回两个数组的所有数中第K小的数.例如:arr1 = {1,2,3,4,5};arr2 = {3,4,5};K = 1;因为1为所有数中最小的,所 ...

  7. LeetCode题目----求中位数---标签:Array

    题目难度---困难 题目要求: 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 . 请找出这两个有序数组的中位数.要求算法的时间复杂度为 O(log (m+n)) . 思路:第一眼 ...

  8. leetcode题目4.寻找两个有序数组的中位数(困难)

    题目描述: 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2. 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n)). 你可以假设 nums1 和  ...

  9. [NOIP2013提高&洛谷P1966]火柴排队 题解(树状数组求逆序对)

    [NOIP2013提高&洛谷P1966]火柴排队 Description 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相 ...

随机推荐

  1. Hdu 4725 The Shortest Path in Nya Graph (spfa)

    题目链接: Hdu 4725 The Shortest Path in Nya Graph 题目描述: 有n个点,m条边,每经过路i需要wi元.并且每一个点都有自己所在的层.一个点都乡里的层需要花费c ...

  2. Solutions to an Equation LightOJ - 1306

    Solutions to an Equation LightOJ - 1306 一个基础的扩展欧几里得算法的应用. 解方程ax+by=c时,基本就是先记录下a和b的符号fla和flb(a为正则fla为 ...

  3. iOS常用第三方库 -转

    转自 http://www.cnblogs.com/jukaiit/p/4956419.html 1.AFNetworking 轻量级的通讯类库,使用非常简单. 下载地址:https://github ...

  4. python正则表达式多次提取数据(一个规则提取多组数据)

    import re ttt='"FileName":"陈雪凝 - <em>绿色<\/em>","AlbumID":& ...

  5. 1049 - One Way Roads 观察 dfs

    http://lightoj.com/volume_showproblem.php?problem=1049 题意是,在一副有向图中,要使得它变成一个首尾相连的图,需要的最小代价. 就是本来是1--& ...

  6. HDU 1223 打表 + 大数

    http://acm.hdu.edu.cn/showproblem.php?pid=1223 一般遇到这些题,我都是暴力输出前几项,找规律.未果. 然后输出n = 1时候,以A开始,有多少个答案, n ...

  7. HDU 1220 B - Cube

    http://acm.hdu.edu.cn/showproblem.php?pid=1220 一开始的做法是,先暴力算出一个面,就是n * n的面,能有多少对.记作face 然后从上开始算下来,最上一 ...

  8. WebStorm 10.0.3注册码

    UserName:William ===== LICENSE BEGIN ===== 45550-12042010 00001SzFN0n1bPII7FnAxnt0DDOPJA INauvJkeVJB ...

  9. asp.net core教程 (一)

    Asp.Net Core简介 ASP.NET Core 是一个全新的开源.跨平台框架,可以用它来构建基于网络连接的现代云应用程序,比如:Web 应用,IoT(Internet Of Things,物联 ...

  10. oracle 数据导入、导出

    导入导出 --数据导出备份和导入 ------注意 导出和导入 必须是CMD 命令行下操作,而不是SQL编辑器中 --1.导出表 . --exp:导出关键字 ,userid:用户权限 ,file:保存 ...