kmjp's blog

競技プログラミング参加記です

AtCoder ABC #169 : E - Count Median

遠回りしすぎたけど反省のため書いておく。
https://atcoder.jp/contests/abc169/tasks/abc169_e

問題

N要素の整数列がある。i番目の値は[A[i],B[i]]の範囲を取るとする。
中央値としてあり得るのは何通りか。

解法

中央値の最小値をX、最大値をYとすると、Nが奇数なら[X,Y]の範囲を1ごとに、偶数なら1/2ごとの値が取れる。
あとはX,Yを求めればよい。

自分は無駄に二分探索で頑張ったのだがAの中央値がX、Bの中央値がYになるのだそうで。
以下無駄に二分探索してしまったコード。

int N;
int L[202020],R[202020];
int S[2][402020];

int ok1(int v,int tar) {
	int C[3]={};
	int i;
	FOR(i,N) {
		if(R[i]<v) C[0]++;
		else if(v<L[i]) C[2]++;
		else C[1]++;
	}
	
	return C[0]<tar;
}

int ok2(int v,int tar) {
	int C[3]={};
	int i;
	FOR(i,N) {
		if(R[i]<v) C[0]++;
		else if(v<L[i]) C[2]++;
		else C[1]++;
	}
	
	return C[2]<tar;
}

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N;
	vector<int> V;
	FOR(i,N) {
		cin>>L[i]>>R[i];
		V.push_back(L[i]);
		V.push_back(R[i]+1);
	}
	
	int ma[2]={};
	int mi[2]={1<<30,1<<30};
	FOR(i,2) {
		int tar;
		if(N%2==0) {
			tar=N/2+i;
		}
		else {
			tar=(N+1)/2;
		}
		
		for(j=29;j>=0;j--) {
			if(ok1(ma[i]+(1<<j),tar)) ma[i]+=1<<j;
			if(ok2(mi[i]-(1<<j),tar)) mi[i]-=1<<j;
		}
	}
	
	//cout<<mi[0]<<" "<<mi[1]<<" "<<ma[0]<<" "<<ma[1]<<endl;
	if(N%2==0) {
		cout<<(ma[1]+ma[0]-mi[0]-mi[1])+1<<endl;
	}
	else {
		cout<<ma[0]-mi[0]+1<<endl;
	}
	
	
	
}

まとめ

上位がかなり短時間で解いてるし、これはおかしいかもとは思ったんだけど、500ptだしやりかねないかな…と。