标签:
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5857
题意:给出一个已排好的序列,再给出两个范围(l1,r1,l2,r2),求由着两个子序列 组成的新序列的中位数,结果保留一位小数。
官方题解:
一个数组上的两个区间求中位数,可以通过分类讨论直接找到中位数,复杂度O(1).不过本题数据较小,优美的log(n)也可过.
分析:我用的是前者的方法。弄一个函数求新序列排第X在原序列的下标,如果长度是奇数,直接求排在第len/2+1位上的,偶数则中间两个的平均数。
找之前我先处理了一下,让l1<=l2。
中位数:将序列排好序后取中间的数,偶数序列则为中间二数和除2;
函数中主要讨论三种情况,一种是l2>=r1(1 2 3 4),这种最简单,直接找,第二种是有重叠部分(类似1 3 2 5),第三种(类似1 5 2 3)是第二串是第一串的子串,这种我发现和第二种是一样的,于是直接转化成第二种。(例如 1 5 2 3和1 3 2 5结果肯定是一样的);
(ps:由于复制后修改了第二种忘记改第三种了,于是WA了两次。)
代码:
#include<cstdio> #include<cmath> #include<cstring> #include<queue> #include<stack> #include<cstdlib> #include<iomanip> #include<string> #include<vector> #include<map> #include<string> #include<iostream> #include<algorithm> using namespace std; #define INF 0x3f3f3f3f typedef long long ll; #define Max(a,b) (a>b)?a:b #define lowbit(x) x&(-x) int l1,l2,r1,r2,sum; double a[100005]; double ans(int x) { if(r1<=l2) { if(x<=r1-l1+1) { return a[l1+x-1]; } else { return a[l2+x-1-r1+l1-1]; } } else if(r1<=r2) { if(x<=l2-l1) { return a[l1+x-1]; } else if(x>r1-l1+1+r1-l2+1) { return a[l2+x-r1+l1-1-1]; } else { return a[l2+(x-l2+l1+1)/2-1]; } } else { swap(r1,r2); if(x<=l2-l1) { return a[l1+x-1]; } else if(x>r1-l1+1+r1-l2+1) { return a[l2+x-r1+l1-1-1]; } else { return a[l2+(x-l2+l1+1)/2-1]; } } } int main() { int t; scanf("%d",&t); while(t--) { int n,m; scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) { scanf("%lf",&a[i]); } for(int i=0; i<m; i++) { scanf("%d%d%d%d",&l1,&r1,&l2,&r2); if(l1>l2) { swap(l1,l2); swap(r1,r2); } sum=r1-l1+1+r2-l2+1; if(sum%2) { printf("%.1f\n",ans(sum/2+1)); } else { printf("%.1f\n",(ans(sum/2)+ans(sum/2+1))/2); } } } }
HDU 5857 Median (2016 多校训#10 1001)
标签:
原文地址:http://www.cnblogs.com/wwdf/p/5785489.html