AtCoder ARC 101 D Median of Medians(逆序对)
Posted harryhqg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder ARC 101 D Median of Medians(逆序对)相关的知识,希望对你有一定的参考价值。
题意:
给一个数组,取每一段区间的中位数重新构成一个一个数组,求出该数组的中位数
中位数是指序列中A的第$frac{|A|}{2}+1$个元素
分析:
刚读完题感觉此题很神,做完之后发现确实很神,不得不赞叹Atcoder出题人太强了。。。
考虑二分答案。
我们二分最后的中位数是mid,把原序列大于mid的数变成1,小于等于的是-1
之后处理出前缀和sum
然后发现一个重要的性质:只要一段区间的和大于0,那么这段区间的中位数就一定大于等于mid
于是要求的答案就转化成了当前序列中的顺序对($i < j && a[i] < a[j]$)个数。
大家肯定知道逆序对的求法可以通过树状数组和归并排序解决,那么顺序对也一样的,笔者用的是树状数组去求。
如果算出来的顺序对个数$>n*(n-1)/4$就是$return true$(n*(n-1)个区间的中间是要在/2)
于是问题就被完美解决了
代码:
#include <map> #include <set> #include <cmath> #include <ctime> #include <queue> #include <stack> #include <vector> #include <bitset> #include <cstdio> #include <cctype> #include <string> #include <cstring> #include <cassert> #include <climits> #include <cstdlib> #include <iostream> #include <algorithm> #include <functional> using namespace std ; #define rep(i, a, b) for (int (i) = (a); (i) <= (b); (i)++) #define Rep(i, a, b) for (int (i) = (a) - 1; (i) < (b); (i)++) #define REP(i, a, b) for (int (i) = (a); (i) >= (b); (i)--) #define clr(a) memset(a, 0, sizeof(a)) #define Sort(a, len, cmp) sort(a + 1, a + len + 1, cmp) #define ass(a, sum) memset(a, sum, sizeof(a)) #define ls ((rt) << 1) #define rs ((rt) << 1 | 1) #define lowbit(x) (x & -x) #define mp make_pair #define pb push_back #define fi first #define se second #define endl ‘ ‘ #define ENDL cout << endl #define SZ(x) ((int)x.size()) typedef long long ll ; typedef unsigned long long ull ; typedef vector <int> vi ; typedef pair <int, int> pii ; typedef pair <ll, ll> pll ; typedef map <int, int> mii ; typedef map <string, int> msi ; typedef map <ll, ll> mll ; const int N = 100010 ; const double eps = 1e-8 ; const int iinf = INT_MAX ; const ll linf = 2e18 ; const double dinf = 1e30 ; const int MOD = 1000000007 ; inline int read(){ int X = 0, w = 0 ; char ch = 0 ; while (!isdigit(ch)) { w |= ch == ‘-‘ ; ch = getchar() ; } while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar() ; return w ? - X : X ; } void write(int x){ if (x < 0) putchar(‘-‘), x = - x ; if (x > 9) write(x / 10) ; putchar(x % 10 + ‘0‘) ; } void print(int x) { cout << x << endl ; exit(0) ; } void PRINT(string x) { cout << x << endl ; exit(0) ; } void douout(double x){ printf("%lf ", x + 0.0000000001) ; } int a[N], sum[N * 10], bit[N * 10] ; int n, l, r ; void add(int a) { for (; a <= 2 * N; a += lowbit(a)) bit[a]++ ; } int query(int a){ int res = 0 ; for (; a; a -= lowbit(a)) res += bit[a] ; return res ; } int check(int x) { for (int i = 0; i <= 2 * N; i++) bit[i] = 0 ; clr(sum) ; for (int i = 1; i <= n; i++) { sum[i] = sum[i - 1] + (a[i] >= x ? 1 : -1) ; } ll ans = 0 ; for (int i = 0; i <= n; i++) { ans += query(sum[i] + N) ; add(sum[i] + N) ; } return ans >= 1ll * n * (n + 1) / 4 ; } signed main(){ scanf("%d", &n) ; for (int i = 1; i <= n; i++) scanf("%d", &a[i]), r = max(r, a[i]) ; while (l <= r) { int mid = (l + r) >> 1 ; if (check(mid)) l = mid + 1 ; else r = mid - 1 ; } printf("%d ", r) ; } /* 写代码时请注意: 1.是否要开Long Long?数组边界处理好了么? 2.实数精度有没有处理? 3.特殊情况处理好了么? 4.做一些总比不做好。 思考提醒: 1.最大值和最小值问题可不可以用二分答案? 2.有没有贪心策略?否则能不能dp? */
以上是关于AtCoder ARC 101 D Median of Medians(逆序对)的主要内容,如果未能解决你的问题,请参考以下文章