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\) 个饭店吃的食物量。
- \(\forall_{1\ \leq\ i\ \leq\ n},\ \sum_{j\ =\ 1}^m\ eat_{i,\ j}\ =\ a_i\);
- \(\forall_{1\ \leq\ i\ \leq\ n},\ \max\{x_j\ |\ eat_{i,\ j}\ >\ 0\}\ +\ a_i\ \leq\ t\);
- \(\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;
}