Lilliput Steps

小さな一歩から着実に. 数学やプログラミングのことを書きます.

IOI 2011-day1 Rice Hub

問題文 : 米集積場 (pdf注意)

解法 :
C(x) : Bバーツ以内でx個の水田から米を届けられるか, とすると,
C(A)が成り立つ時, C(A - 1)も成立する. よって, xについて二分探索を行う.

このとき, 集める水田が連続していたほうがいいことは明らかなので, R - x個の, 連続するx個の水田の集合について, Bバーツ以内で米を届けられる最短地点を探す.
このとき, その集合の中央の水田に集積場をたてることが最適なので, 中央に集めて確認をする.
こうすることで, 米を集められる水田の最大値が求まる.

コード :

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long ll;

int besthub(int R, int L, int *X, ll B)
{
	int left, right, center;
	ll rSum[100000];
	left = 1, right = R;
	
	for (int i = 0; i < R; i++){
		if (!i) rSum[i] = X[i];
		else rSum[i] = rSum[i - 1] + X[i];
	}
	
	while (left != right){
		center = (left + right + 1) / 2;
		bool ok = false;
		for (int i = 0; i <= R - center; i++){
			int a = i, b = i + center - 1;
			int p1 = (a + b) / 2, p2 = (a + b) / 2 + 1;
			ll c1 = p1 - a + 1, c2 = c1 + 1;
			ll cost1 = X[p1] * c1 - (rSum[p1] - (a ? rSum[a - 1] : 0)) + (rSum[b] - (p1 ? rSum[p1] : 0)) - X[p1] * (center - c1);
			ll cost2 = X[p2] * c2 - (rSum[p2] - (a ? rSum[a - 1] : 0)) + (rSum[b] - (p2 ? rSum[p2] : 0)) - X[p2] * (center - c2);
			if (min(cost1, cost2) <= B){
				ok = true;
				break;
			}
		}
		if (ok == true){
			left = center;
		}
		else {
			right = center - 1;
		}
	}
	
	return (left);
}