51nod1685:第K大區間2

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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章