题意:

给定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. Jamie and Interesting Graph CodeForces - 916C

    http://codeforces.com/problemset/problem/916/C 好尬的题啊... #include<cstdio> #include<algorithm ...

  2. Subsequence HDU - 3530

    Subsequence HDU - 3530 方法:单调队列区间最大最小 错误记录(本地写错)的原因:写成每次试着扩展右端点,却难以正确地处理"在多扩展右端点之后减去多扩展的部分" ...

  3. Codeforces Round #323 (Div. 2)

    被进爷坑了,第二天的比赛改到了12点 水 A - Asphalting Roads /************************************************ * Author ...

  4. BestCoder Round #54 (div.2) 1003 Geometric Progression

    题目传送门 题意:判断是否是等比数列 分析:高精度 + 条件:a[i] * a[i+2] == a[i+1] * a[i+1].特殊情况:0 0 0 0 0是Yes的,1 2 0 9 2是No的 代码 ...

  5. c库函数-字符串

    一 strok:从字符串中按照分隔符提取所有字串 char s[] = "水发产品,47.6,不合格,mg/kg,17-05-21 15:04;";  char *delim = ...

  6. HAL之串口

    在STM32cubeMX中 1 外设功能打开 2 GPIO对应管脚的串口功能打开 3 对应GPIO引脚的配置 4串口的配置,中断的设置 在MDK中 5.1 串口初始化MX_USART1_UART_In ...

  7. azkaban web ui界面出现异常诡异“丑”界面的问题解决(图文详解)

    前期博客 启动azkaban时出现User xml file conf/azkaban-users.xml doesn't exist问题解决(图文详解) 问题详情 [hadoop@master co ...

  8. 前端之HTML样式

    <!doctype html> h5的文档声明 <html> 网页的根标签(根元素 html)--所有的代码都放置在此内 <head> <meta chars ...

  9. 问题处理:Cannot find module (SNMPv2-TC): At line 10 in /usr/share/snmp/mibs/UCD-DLMOD-MIB.txt

    在执行  php -i |grep redis 时显示以下报错信息(但在phpinfo查看时一切正常): MIB search path: /root/.snmp/mibs:/usr/share/sn ...

  10. windows session logoff时进行处理动作

    目标:Windows session logoff时得到通知,进行一些记录/清理工作 测试平台: win7 x64 logoff时系统会发送WM_ENDSESSION消息,如果某个应用对这个消息的处理 ...