https://yukicoder.me/problems/no/545
解説放送
https://youtu.be/dTb6XHsWzxk?t=400
※ 12:43 付近で-37を転記ミスして-3と書いています(間違えました)
前提知識
- 半分全列挙
解法
https://yukicoder.me/submissions/188780
N個の品物を2つに分ける。
二つに分けた先で、「A君の満足度-B君の満足度」としてあり得る値を全列挙する。
片方のありうる値について全探索して、A君の満足度とB君の満足度の差を最小化する。
グループAのありうる値xについて考えるとき、グループBの全てに対して差を考えるのは無駄である。
実際考えるべき値は-x周辺であり、その部分だけを見つけくればよい。
これはグループBのありうる値を予めソートしておき、lower_boundで-xを探す。
考えるべき値は-x以上の数と、その一つ前の数である(下の解法では一つ後の数も一応やってる)。
これをチェックすれば答えが得られる。
typedef long long ll; int N; ll A[40], B[40]; //--------------------------------------------------------------------------------------------------- vector<ll> solve(vector<int> &a) { vector<ll> res; int n = a.size(); rep(mask, 0, 1 << n) { ll d = 0; rep(i, 0, n) { if (mask & (1 << i)) d += A[a[i]]; else d -= B[a[i]]; } res.push_back(d); } sort(res.begin(), res.end()); res.erase(unique(res.begin(), res.end()), res.end()); return res; } //--------------------------------------------------------------------------------------------------- #define INF 1LL<<60 void _main() { cin >> N; rep(i, 0, N) cin >> A[i] >> B[i]; vector<int> a, b; rep(i, 0, N) { if (i % 2 == 0) a.push_back(i); else b.push_back(i); } auto aa = solve(a); auto bb = solve(b); ll ans = INF; fore(i, aa) { int j = lower_bound(bb.begin(), bb.end(), -i) - bb.begin(); ll mi = INF; if (0 <= j && j < bb.size()) mi = min(mi, abs(i + bb[j])); if (0 <= j - 1 && j - 1 < bb.size()) mi = min(mi, abs(i + bb[j - 1])); if (0 <= j + 1 && j + 1 < bb.size()) mi = min(mi, abs(i + bb[j + 1])); ans = min(ans, mi); } cout << ans << endl; }