SRM739Medium

题意

\(n\) 头牛,每头牛要吃 \(a_i\) 个食物,初始时,每头牛都在 \(0\) 上。有 \(m\) 个饭店,第 \(i\) 个饭店再 \(x_i\) 上,每个饭店每天可以给最多 \(1\) 头牛提供 \(1\) 个食物。每一天,每头牛可以选择向前后走一步,或者吃这个位置上饭店的食物。
问最少多少天所有牛都吃好。

\(1\ \leq\ n,\ m\ \leq\ 300,\ 1\ \leq\ a_i,\ x_i\ \leq\ 10^9\)

做法1

二分答案 \(t\),考虑如何检验。
可以发现若 \(a_i\ +\ x_j\ >\ t\) 则第 \(i\) 头牛不能吃第 \(j\) 个饭店的食物。
\(eat_{i,\ j}\) 表示第 \(i\) 头牛在第 \(j\) 个饭店吃的食物量。

  1. \(\forall_{1\ \leq\ i\ \leq\ n},\ \sum_{j\ =\ 1}^m\ eat_{i,\ j}\ =\ a_i\)
  2. \(\forall_{1\ \leq\ i\ \leq\ n},\ \max\{x_j\ |\ eat_{i,\ j}\ >\ 0\}\ +\ a_i\ \leq\ t\)
  3. \(\forall_{1\ \leq\ j\ \leq\ m},\ \sum_{i\ =\ 1}^n\ eat_{i,\ j}\ +\ x_j\ \leq\ t\)

可以证明 \(t\) 存在解,当且仅当存在一组满足以上三个条件的 \(eat\)
考虑贪心,按照牛食量从大到小顺序考虑每头牛的 \(eat_i\),按饭店顺序从左往右贪心填即可。
时间复杂度: \(O((n\ +\ m)\ log\ (a_i\ +\ x_i))\)

代码

#line 2 "HungryCowsMedium.cpp"
#include <bits/stdc++.h>

#ifdef DEBUG
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug(...)
#endif

#ifdef __WIN32
#define LLFORMAT "I64"
#define Rand() ((rand() << 15) + rand())
#else
#define LLFORMAT "ll"
#define Rand() (rand())
#endif


using namespace std;

class HungryCowsMedium {
	public:
	long long getWellFedTime(vector <int> cowAppetites, vector <int> barnPositions) ;
	
// BEGIN CUT HERE
	public:
	void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); }
	private:
	template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); }
	void verify_case(int Case, const long long &Expected, const long long &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } }
	void test_case_0() { int Arr0[] = {3}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {5}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); long long Arg2 = 8LL; verify_case(0, Arg2, getWellFedTime(Arg0, Arg1)); }
	void test_case_1() { int Arr0[] = {1,1,1,1,1}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {2,3}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); long long Arg2 = 5LL; verify_case(1, Arg2, getWellFedTime(Arg0, Arg1)); }
	void test_case_2() { int Arr0[] = {4,4,4}; vector <int> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {4,2}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); long long Arg2 = 9LL; verify_case(2, Arg2, getWellFedTime(Arg0, Arg1)); }

// END CUT HERE

} ___test;

// BEGIN CUT HERE
int main() {
	int test_case;
	scanf("%d", &test_case);
	___test.run_test(test_case);
}
// END CUT HERE

//----------head----------

long long HungryCowsMedium::getWellFedTime(vector <int> A, vector <int> B) {
	sort(A.begin(), A.end()); reverse(A.begin(), A.end());
	sort(B.begin(), B.end());

	auto check = [&](long long x) {
		deque<pair<long long, int> > b(B.size());
		for (int i = 0; i < b.size(); ++i) b[i] = make_pair(max(x - B[i], 0ll), B[i]);
		for (auto iA: A) {
			long long a = iA; int lst;
			while(b.size() && a) {
				long long x = min(a, b[0].first);
				a -= x;
				lst = b[0].second;
				b[0].first -= x;
				if(!b[0].first) b.pop_front();
			}
			if(a || iA + lst > x) return 0;
		}
		return 1;
	};

	long long l = 0, r = (1ll << 40);
	while(l <= r) {
		long long mid = l + r >> 1;
		if(check(mid)) r = mid - 1;
		else l = mid + 1;
	}
	return l;
}
posted @ 2018-10-15 12:18  King_George  阅读(172)  评论(0编辑  收藏  举报