Official

G - The baggage Editorial by mechanicalpenciI


結論から言うと、次のように荷物を割り振るのが最善で、最後のステップまで行った後に荷物が残っていないならば答えは Yes 、残っているならば答えは No となります。 以下、ある時点でのある人の体力\(-\)(現在持っている荷物の重さ)を 残り体力 と書くことにします。

  • ステップ \(1\) : 体力 \(5\) の人が重さ \(5\) の荷物を持つ。(体力 \(5\) の人か重さ \(5\) の荷物がなくなるまで繰り返す。以下同様)
  • ステップ \(2\) : 体力 \(4\) の人が重さ \(4\) の荷物を持つ。
  • ステップ \(3\) : 体力 \(5\) の人が重さ \(4\) の荷物を持つ。
  • ステップ \(4\) : 体力 \(3\) の人が重さ \(3\) の荷物を持つ。
  • ステップ \(5\) : 体力 \(5\) の人が重さ \(3\) の荷物を持つ。
  • ステップ \(6\) : 体力 \(4\) の人が重さ \(3\) の荷物を持つ。
  • ステップ \(7\) : 残り体力が \(2\)以上 の人が重さ \(2\) の荷物を持つ。
  • ステップ \(8\) : 残り体力が \(1\)以上 の人が重さ \(1\) の荷物を持つ。

最後まで行って荷物が残っていなかったならば 答えが Yes なことは明らかです。 それぞれの重さの荷物が残ったとして、答えが No なことを証明していきます。対偶をとり、条件をみたす割り当て方があるならばそれぞれの重さの荷物が残らないことをしめせば十分です。

まず、重さが \(5\), \(4\), \(3\) のときは明らかです。 どの人も\(3\) 以上の重さの荷物を高々 \(1\) つしか持てないため、 条件をみたす割り当て方があるならば、

\[ A_5\leq B_5, \quad A_4+A_5\leq B_4+B_5, \quad A_3+A_4+A_5\leq B_3+B_4+B_5 \]

が成り立ちます。 それぞれステップ \(1\), \(3\), \(6\) の終了時点を考えると、 これが成り立っているならば、上のように割り当てを行ったとき、重さが \(5\) , \(4\), \(3\) の荷物が残らない事が分かります。

次に、重さ \(2\) の荷物についてです。 条件をみたす割り当て方をとり、重さ \(5\), \(4\), \(3\) の荷物を持った人の体力をそれだけ取り除いたときのものを考えます。 このとき、

\[ A_2\leq \frac{1}{2}\times\left( (残り体力の総和)-(残り体力が奇数の人数) \right) \]

が成り立っています。\((残り体力の総和)\)は重さが \(3\)以上の荷物の割り当て方によらず、\((残り体力が奇数の人数) \)は、
\(B_1+B_3+B_5-(重さ5の荷物を持った体力 5の人の人数)-(重さ3の荷物を持った体力 3の人の人数)-(重さ3の荷物を持った体力 5の人の人数)+(重さ3の荷物を持った体力 4の人の人数)\)
\(=B_1+B_3+B_5-A_3-A_5+2\times (重さ3の荷物を持った体力 4の人の人数) \)
となります。これが上のアルゴリズムに沿った割り当て方において条件をみたす割り当て方におけるそれより小さければよいです。よって、示さなければならないのは、上のようにステップ \(6\) まで割り当てたときの 「重さ3の荷物を持った体力 \(4\) の人の人数」が、重さ \(3\) 以上の荷物を条件をみたすように割り当てる方法すべての中で最小となっていることです。この最小値は順に考えていく事で \(\max(0,A_3-B_3-(B_5-A_5-\max(A_4-B_4,0)))\) と書かれる事が分かり、上のように割り当てたときこれが達成されることは明らかです。

最後に重さ \(1\) の荷物についてです。

条件をみたす割り当て方の存在から、

\[ A_1+2A_2+3A_3+4A_4+5A_5 \leq B_1+2B_2+3B_3+4B_4+5B_5 \]

が成り立ちます。このとき、ステップ \(8\) の後で荷物 \(1\) が残らないことは明らかです。

以上より、上の割り当て方の正当性が証明されました。 このシミュレーションはそれぞれの残り体力の人の人数及び重さの荷物の個数を操作する事で各ステップ \(O(1)\) で行う事が出来ます。よって、各テストケースあたり \(O(1)\) で判定でき、この問題を解く事が出来ました。

c++ による実装例:

#include <bits/stdc++.h>
using namespace std;

#define N 200010
#define MOD (ll)998244353
#define ll long long
#define rep(i, n) for(int i = 0; i < n; ++i)

ll a[6];
ll b[6];

void pack(ll x, ll y) {
	ll c = min(a[x], b[y]);
	a[x] -= c;
	b[y] -= c;
	b[y - x] += c;
	return;
}

int main(void) {
	ll t;
	bool ans;
	cin >> t;
	rep(tt, t) {
		rep(i, 5)cin >> a[i + 1];
		rep(i, 5)cin >> b[i + 1];
		a[0] = 0;
		b[0] = 0;

		pack(5, 5);
		pack(4, 4);
		pack(4, 5);
		pack(3, 3);
		pack(3, 5);
		pack(3, 4);
		rep(i, 4)pack(2, 5 - i);
		rep(i, 5)pack(1, 5 - i);

		ans = true;
		rep(i, 5)if (a[i + 1] > 0)ans = false;
		if (ans)cout << "Yes" << endl;
		else cout << "No" << endl;
	}

	return 0;
}

posted:
last update: