Particle

競技プログラミングについての雑記

AOJ 0617: Ball

良問

解法

nが3^*のときは解を二分探索すると解けるから、ダミーの貴族を追加する。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 401000
int d1[N], p[N], d2[N], d[N], s[N];
int n, m, n2;
int rest, off, lm;

int rec(int l, int r){
	if(r-l==1){
		if(s[l]==-1) return 1;
		if(s[l]==1) return 0;
		return N;
	}
	int a[3], w = (r-l)/3;
	for(int i = 0; i < 3; i++)
		a[i] = rec(l+w*i, l+w*(i+1));
	sort(a, a+3);
	return min(N, a[0]+a[1]);
}

int main(){
	scanf("%d%d", &n, &m);
	for(int i = 0; i < m; i++) scanf("%d%d", d1+i, p+i);
	for(int i = 0; i < n-m; i++) scanf("%d", d2+i);
	memcpy(d, d1, m*sizeof(int));
	memcpy(d+m, d2, (n-m)*sizeof(int));
	sort(d, d+n);
	int th = 3, cth = 1;
	while(th < n){
		th *= 3;
		cth++;
	}
	rest = (th-n)/2; off = rest*3; lm = n-rest;
	for(int i = 0; i < m; i++){
		if(p[i]>lm) p[i] = (p[i]-lm-1)*3;
		else p[i] = p[i]-1+off;
	}
	int lb = 0, ub = n;
	while(ub-lb>1){
		int md = (lb+ub)/2;
		int t = d[md];
		memset(s, -1, sizeof(s));
		for(int i = 0; i < rest; i++){
			s[3*i+1] = 0;
			s[3*i+2] = 1;
		}
		for(int i = 0; i < m; i++)
			s[p[i]] = d1[i]>=t;
		int sm = 0;
		for(int i = 0; i < n-m; i++)
			sm += d2[i]>=t;
		int nm = rec(0, th);
		if(nm<=sm) lb = md;
		else ub = md;
	}
	printf("%d\n", d[lb]);

	return 0;
}