题意:

给定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. IOCP编程之基本原理

    在我的博客之前写了很多关于IOCP的“行云流水”似的看了让人发狂的文章,尤其是几篇关于IOCP加线程池文章,更是让一些功力不够深厚的初学IOCP者,有种吐血的感觉.为了让大家能够立刻提升内力修为,并且 ...

  2. CSS选择器优先级【转】

    样式的优先级 多重样式(Multiple Styles):如果外部样式.内部样式和内联样式同时应用于同一个元素,就是使多重样式的情况. 一般情况下,优先级如下: (外部样式)External styl ...

  3. two_sum问题

    def two_sum(li, target): for i in range(len(li)): for j in range(i+1, len(li)): if li[i] + li[j] == ...

  4. 洛谷 P3480 [POI2009]KAM-Pebbles

    https://www.luogu.org/problemnew/solution/P3480 讲不清楚... 首先对原序列做差分:设原序列为a,差分序列为d 那么,每一次按题意在原序列位置i处取走石 ...

  5. LookupError: unknown encoding: idna 的处理方法

    写了一个脚本,想把它打包成exe文件,在python编译器中运行正常,但是打包成.exe文件运行报错 LookupError: unknown encoding: idna 找遍资料终于找到了解决方法 ...

  6. python关于文件的一些记录

    1.文件打开: file("data.txt")或open("data.txt")注意不要漏了文件的后缀.(不加参数时,file为你默认为'r',reading ...

  7. 关于list,字符串的小记录

    1.关于操作list的命令: a.append("hi") 这个可以在list的最后一项加上个这个字符串"hi",a是list的名字. del a[3] 删去l ...

  8. Unity项目学习笔记

    1.TCP和IP IP:主要作用是在复杂的网络环境中将数据包发送给的最终的目标地址. 端口号:系统会分给系统端口号  一般知名的端口号在0-1023之间,而我们经常使用的自定义/动态分配的端口号则一般 ...

  9. 安装mysql时 make 时 提示 redeclaration of C++ built-in type ‘bool’ 错误

    安装mysql时 make 时 提示 redeclaration of C++ built-in type ‘bool’ 错误 由于gcc-c++是在./configure后进行编译的 重新./con ...

  10. Java练习题02

    问题: 编程求一个整数数组的最大值.最小值.平均值和所有元素的和. 代码: public class Page99{     public static void main(String args[] ...