基準時間限制: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;
}