基准时间限制:1.5 秒 空间限制:131072 KB 分值: 160
难度:6级算法题
定义一个长度为奇数的区间的值为其所包含的的元素的中位数。中位数_百度百科
现给出n个数,求将所有长度为奇数的区间的值排序后,第K大的值为多少。
样例解释:
[l,r]表示区间的值
[1]:3
[2]:1
[3]:2
[4]:4
[1,3]:2
[2,4]:2
第三大是2
Input
第一行两个数n和k(1<=n<=100000,k<=奇数区间的数量) 第二行n个数,0<=每个数<2^31
Output
一个数表示答案。
Input示例
4 3 3 1 2 4
Output示例
2
二分答案t,统计中位数大于等于t的区间有多少个。
设a[i]为前i个数中有a[i]个数>=t,若奇数区间[l,r]的中位数>=t,则(a[r]-a[l-1])*2>r-l+1,即(a[r]*2-r)>(a[l-1]*2-l+1)。
设b[i]=a[i]*2-i,统计每个b[i]有多少个b[j]<b[i](j<i 且 j和i奇偶性不同)
总复杂度O(nlognlogn)
卡在统计上了,想用multiset二分发现不成,树状数组记录前面b[x]的值,直接统计。
代码:
//#pragma comment(linker, "/STACK:102400000,102400000")
#pragma warning(disable:4996)
#include <fstream>
#include <iostream>
#include <functional>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define LL_INF 0x3fffffffffffffff
#define INT_INF 0x3fffffff
#define mem(a, b) memset(a, b, sizeof(a))
#define pper(i,n,m) for(int i = n;i >= m; i--)
#define repp(i, n, m) for (int i = n; i <= m; i++)
#define rep(i, n, m) for (int i = n; i < m; i++)
#define sa(n) scanf("%d", &(n))
#define mp make_pair
#define ff first
#define ss second
#define pb push_back
const int maxn = 4 * 200005;
const ll mod = 1e9 + 7;
const double PI = acos(-1.0);
ll n, k;
ll val[maxn], b[maxn];
ll d[2][maxn];
int lowbit(int x)
{
return x&(-x);
}
void add(int pos, int x, int v)
{
while (x <= maxn)
{
d[pos][x] += v;
x += lowbit(x);
}
}
ll get(int pos, int x)
{
ll res = 0;
while (x > 0)
{
res += d[pos][x];
x -= lowbit(x);
}
return res;
}
bool check(ll x)
{
ll i, j;
mem(b, 0);
for (i = 1; i <= n; i++)
{
if (val[i] >= x)
{
b[i] = 1 + b[i - 1];
}
else
{
b[i] = b[i - 1];
}
}
for (i = 1; i <= n; i++)
{
b[i] = b[i] * 2 - i;
}
mem(d, 0);
ll res = 0, sum = 0;
add(0, 2 * n, 1);
for (i = 1; i <= n; i++)
{
res += get(!(i & 1), 2 * n + b[i] - 1);
add(i & 1, 2 * n + b[i], 1);
}
return res >= k;
}
void solve()
{
ll i, j;
scanf("%lld%lld", &n, &k);
for (i = 1; i <= n; i++)
{
scanf("%lld", &val[i]);
b[i] = val[i] * 2 - i;
}
ll le = 0, ri = INT_INF;
ll mid;
while (le < ri)
{
mid = (le + ri + 1) / 2;
if (check(mid))
{
le = mid;
}
else
{
ri = mid - 1;
}
}
printf("%lld", le);
}
int main()
{
solve();
return 0;
}