ユニークビジョンプログラミングコンテスト2026 夏(AtCoder Regular Contest 226)A,B,C,D問題メモ

A - Meeting Division

問題文

  • $1,2, \dots ,N$ の番号がついた $N$ 個の会議があります。会議 $i$ の開始時刻は $S_i$、終了時刻は $T_i$ です。
  • 高橋君と青木君は、各会議に $2$ 人のうちちょうど一方を担当者として割り当てようとしています。正の長さの時間帯で重なる $2$ 個の会議を同じ人が担当することはできません。より厳密には、会議 $i$ と会議 $j$ を同じ人が担当することができるのは、$T_i \le S_j$ または $T_j \le S_i$ を満たすときに限ります。
  • 条件を満たす担当者の割り当て方の個数を $998244353$ で割った余りを求めてください。

制約

  • $1 \le N \le 3 \times 10^5$
  • $1 \le S_i \lt T_i \le 2N$
  • $S_1,T_1,S_2,T_2,\dots,S_N,T_N$ は全て異なる
  • 入力される値は全て整数

解法

まず、imos法などによって、同時におこなわれる最大会議数を求める。 「$S_1,T_1,S_2,T_2,\dots,S_N,T_N$ は全て異なる」という制約があるので、ある会議が終わった瞬間に別の会議が始まる可能性はない。実装が少し楽。

最大同時会議数が $3$ 以上なら不可能。$0$ 通り。

$2$ 以下の場合、可能なのだが、2つの系統が互いに重なり合う関係になっている場合、途中で系統を交替することはできない。

系統1   |--------| |-----| |-----------| ...  ←どちらかはずっと高橋君、
系統2     |--| |-----| |----| |--| |-|   ...    もう一方はずっと青木君でないといけない

交替することができるのは、両方の系統で会議が行われていないタイミングに限られる。

                                         v ここ
系統1   |--------| |-----| |-----------|   |---| |---| ...
系統2     |--| |-----| |----| |--| |-|       |-----|   ...

この回数は、imos法で累積和が $0$ になった回数と一致する。その回数を $k$ とし、$2^k$ が答え。

Python3

B - Bin-ary Packing

問題文

  • $1,2,\dots,N$ の番号がついた $N$ 個の袋があります。また、各 $i=0,1,\dots,M-1$ について、重さ $2^i$ の荷物が $A_i$ 個あります。荷物は合計 $A_0+A_1+\dots+A_{M-1}$ 個です。
  • 全ての荷物を、それぞれいずれか $1$ 個の袋に入れます。空の袋があっても構いません。
  • 各袋について、その袋に入っている全ての荷物の重さの総和を袋の重量と呼びます。
  • $N$ 個の袋の重量の最大値としてあり得る最小の値を求めてください。
  • $T$ 個のテストケースが与えられるので、それぞれについて答えを求めてください。

制約

  • $1 \le T \le 10^5$
  • $1 \le N \le 10^6$
  • $1 \le M \le 40$
  • $0 \le A_i \le 10^6$
  • 全てのテストケースにおける $M$ の総和は $2 \times 10^5$ 以下
  • 入力される値は全て整数

解法

わりと、素直な発想をそのまま実装するだけ、という問題に感じた。

重い荷物からなるべく均等に詰めていく。
均等というのはつまり、「その時点で最も重量が軽い袋を1つ選び、そこに入れる」ことを繰り返すのが正当な手法となる。

重さ $2^i$ までの荷物を詰めた結果、袋 $p,q$ の間で重量に差ができても、 その差分 $|w_p-w_q|$ は、$2^{i-1}$ より軽い荷物ならいずれも(個数が足りれば)必ずぴったり埋めることができる。

同じ重量の袋はまとめて管理する。
$S=\{0:N\}$ で初期化する。暫定重量 $0$ の袋が $N$ 個あることを意味する。

$i=M-1,M-2,...,0$ の順に、以下をすればいい。

  • その時点の $S$ の最大重量を $W$ とする。
  • 重量 $W$ 未満の重さの袋に、$W$ まで荷物を詰めていく。
  • 途中で $A_i$ が無くなったらそれまで。端数も忘れないように詰め、次の $i$ へ。
  • 全て $W$ まで詰め終えても $A_i$ が残っていたら、$N$ 個に残りをなるべく均等に配る。

最終的に全ての袋の中で最大重量が答えとなる。

正当性の略証

$S$ のサイズ(袋の重量の種類数)は、1つの $i$ を処理する毎に高々 $1$ つ増えるのみである。
よって1つのケース $O(M^2)$ で求めることができる。

もし暫定重量の同じ袋をまとめない場合、1つのケースに $O(NM)$ かかってしまう。 テストケース全体を通しての $N$ の総和に対する制約はないので、これだとTLEとなる。

Python3

C - Square Corner Packing

問題文

  • $H$ 行 $W$ 列のマス目があります。上から $i$ 行目、左から $j$ 列目のマスを $(i,j)$ と表します。
  • はじめ、全てのマスは白です。
  • 以下の操作を好きな回数行います。
    • 以下の条件を全て満たす整数 $r,c,s$ を選び、マス $(r,c),(r+s,c),(r,c+s),(r+s,c+s)$ を黒く塗る。
      • $1\le r\lt r+s\le H$
      • $1\le c\lt c+s\le W$
      • マス $(r,c),(r+s,c),(r,c+s),(r+s,c+s)$ が全て白。
  • 行うことができる操作回数の最大値を求め、その最大値を達成する操作列を $1$ つ出力してください。
  • $T$ 個のテストケースが与えられるので、それぞれについて答えを求めてください。

制約

  • $1\le T\le 500$
  • $2\le H,W\le 500$
  • 全てのテストケースにおける $HW$ の総和は $250000$ 以下
  • 入力される値は全て整数

解法

「正方形の角になる4マス」を、被らないようになるべく多く取りなさい、という問題。

できる操作の自由度が高すぎて、しばらく「$2 \times 2$ を敷き詰めれば自明では?」となってしまった。
実際、$H$ または $W$ が偶数なら、それが正解となる。

1つの操作毎に、行・列ともに、$2$ マスが必ず塗られる。
$H$ が奇数なら、各列ごとに、必ずどこか1マス以上の奇数マス、塗れないマスができる。
$W$ が奇数なら、各行ごとに、必ずどこか1マス以上の奇数マス、塗れないマスができる。

$2 \times 2$ を敷き詰める解法は、$H$ または $W$ が偶数の場合、 この「絶対に塗れない最小個数」を除いて全て塗ることを達成できる。

曲者なのは、$H,W$ がともに奇数の時である。
そのまま $2 \times 2$ 解法だと $H+W-1$ 個のマスが残ってしまうが、 「どの行・どの列にも必ず1マス以上奇数個の白マスがある」という状態の白マスの最小個数は $\max(H,W)$ である。

問題の操作で塗れるかどうかは一旦無視して、例えば以下のように白マスを残すことができれば、 $2 \times 2$ 解法より多くの操作ができることになる。

2x2解法               もしかすると最適解法
■■■■■■■■□    □■■■■■■■■
■■■■■■■■□    ■□■■■■■■■
■■■■■■■■□    ■■□■■■■■■
■■■■■■■■□    ■■■□■■■■■
□□□□□□□□□    ■■■■□□□□□

小さいケースからあれこれ試行錯誤する。ひとまず対称性を頼りに構築しやすい正方グリッドから。

$1 \times 1, 3 \times 3$ は、さすがに全探索が容易で、無理とわかる。

$5 \times 5$ 以上は、外側の $2$ マスずつを以下のように埋めることで、最小を達成しつつ、$N-4$ のケースに帰着できる。

1 . 2 2 3 3 4 4 1
d d 2 2 3 3 4 4 .
d d . . . . . 5 5
c c . . . . . 5 5
c c . . . . . 6 6
b b . . . . . 6 6
b b . . . . . 7 7
. a a 9 9 8 8 7 7
1 a a 9 9 8 8 . 1

この時、$N=5,9,13,...$ のように、$4$ で割って $1$ 余る奇数なら最小で埋められるが、 $N=3,7,11,...$ のように $3$ 余る奇数の場合は最後で $3 \times 3$ が残り、 どうしても最小より $2$ マス、余分に白マスが生じてしまう。
ただ、1回の操作では必ず $4$ マスが塗られるので、塗るマスを $2$ マスだけ増やすことは不可能である。 よって、後者の場合もこれが最適であることが確認できる。

正方グリッドでは無い場合、短辺側の端に、$N=\min(H,W)$ とした正方グリッドの場合の答えを作る。
そうすると残った部分は一方が偶数になるので、$2 \times 2$ 解法が最適となる。

Python3

D - Penta-Queue

問題文

  • この問題はインタラクティブな問題です。
  • $1$ から $5$ までの番号がついた $5$ 本のキューがあります。はじめ、全てのキューは空です。
  • ジャッジから、以下の $2$ 種類のクエリがそれぞれ $Q$ 回、合計 $2Q$ 回与えられます。
    • push クエリ:ジャッジから整数 $X$ が与えられ、キュー $1$ の末尾に追加される。各 push クエリで与えられる整数 $X$ は全て相異なる。あなたはその後、以下の移動操作を $0$ 回以上行うことができる。
      • 移動操作:$1 \le i,j \le 5$ を満たす整数 $i,j$ を選び、キュー $i$ の先頭の値を取り除いてキュー $j$ の末尾に追加する。ただし、空のキューを $i$ として選ぶことはできない。$i\ne j$ である必要はない。
    • pop クエリ:ジャッジは、$1$ 本以上のキューが空でない状態でのみこのクエリを与える。あなたは $1 \le i \le 5$ を満たす整数 $i$ を選ぶ。このとき、キュー $i$ は空でなく、その先頭の値が、その時点で $5$ 本のキューに入っている全ての値のうち最小でなければならない。その後、ジャッジがキュー $i$ の先頭の値を取り除く。
  • 移動操作は合計で $10^5$ 回までしか行えません。全てのクエリに正しく応答するプログラムを作成してください。

制約

  • $1 \le Q \le 5000$
  • $1 \le X \le 10^9$
  • 各 push クエリで追加される値 $X$ は全て相異なる
  • push クエリと pop クエリはそれぞれ $Q$ 回ずつ与えられる
  • 各 pop クエリが与えられる時点で、$1$ 本以上のキューが空でない
  • 入力される値は全て整数

解法

いつ、何個連続して pop クエリが来るか分からない。 ひょっとすると今ある要素全てを pop することになるかもしれない。 移動操作は push クエリの後にしかできないので、pop クエリの連続の中では並びは変えられない。

そんな中でもクエリに正しく答えるためには、以下が満たされなければならない。

  • pushクエリ+移動操作 の後は、常に全てのキューで要素が昇順に並んでいる

また、操作回数が嵩むのは、push クエリだけ $Q$ 回来た後に pop クエリだけ $Q$ 回来るようなケースである。 途中で pop されて要素が減るのは、昇順を保つ上での制約および操作回数が減るので純粋にメリットしかない。

よって、pop クエリは無いものとして、 push クエリ $Q$ 回を $10^5$ 回までの移動操作で、毎回昇順を保ちながら捌く方法を考えていく。

全体で $10^5$ 回までという制約は、$Q=5000$ として1要素あたりに使える操作回数が平均 $20$ 回ということで、 全要素を毎回昇順に揃える必要があるにしては非常に厳しい。

キュー $1$ に $x$ が追加されたとして、昇順が崩れなければひとまず即座に操作の必要は無い。 (予め何らかの操作をしておいた方がトータルで回数を節約できる、という可能性はあるが、ひとまず後回し)

逆に、昇順が崩れたらキュー $1$ の $x$ 以外の要素は全ていったんは取り出さないといけない。

                 x
Q1   2  3  5  9  4    ←2,3,5,9 までは取り出さないと昇順の崩れを解消できない

せっかく取り出すので、$2,3,5,9$ は $Q2$ など別のキューとマージすることを考える。

Q1   2  3  5  9  4    →    Q1   4
Q2   1  6  8                Q2   1  2  3  5  6  8  9

「各キューの中では常に昇順が保たれている」ので、$Q2$ の要素は昇順に並んでいる前提で良い。
この時、$Q1$ と $Q2$ の先頭同士を比較して、小さい方を $Q2$ の末尾に移す、ということを繰り返せば、 $Q2$ にマージされた数列が完成し、これで再び全キューの昇順が保たれた状態になる。

ただ、これを繰り返していくと $Q2$ が長くなり、1回のマージの操作回数が嵩んでしまう。 そこで、ある程度長くなったらさらに $Q2$ を $Q3$ とマージし、$Q2$ は常に軽く保つことを考える。 連鎖的に、$Q4,Q5$ も以下のようなオーダーの要素数を想定する。

Q1  o o o                       (push クエリ次第)
Q2  o o o o                     (数個)
Q3  o o o o o o o o o o         (数十個)
Q4  o o o o o o o o o o || o o o(数百個)
Q5  o o o o o o o o o o || o o o(数千個)

例えば、 「$Q2$ は、要素数が $10$ 以上になったら $Q3$ とマージし、空にする」 「$Q3$ は、要素数が $100$ 以上になったら $Q4$ とマージし、空にする」… というルールを定めておく。

$Q2$ が空の状態で、$Q1$ から移されてきた要素は、$Q3$ に移されるまで、 ($Q1$ から移される時の操作も含めて)$10$ 回、$Q2$ の中をぐるぐるすることになる。
2回目で入った要素は $9$ 回、3回目は $8$ 回、、、となり、10回目であふれて $Q3$ にマージされる。これが繰り返される。

$Q1→Q2$ 部分の操作は、全体を通して $(1+2+...+10)\times 10 \times \frac{Q}{100}$ となる。

同じことが $Q2→Q3,Q3→Q4,Q4→Q5$ の時も発生する。これらは1回発生したときの操作回数が嵩むが、頻度は少ない。 一般化すると、

  • $\sum_{i=1}^{4}55 \times 10^i \times \frac{Q}{10^{i+1}}$

のように定式化できる。ただ、これは $22 Q$ となり、$20$ 回平均をやや超えてしまう。

基数を $10$ でなくて $9$ にすればよい。
つまり、キュー $i$($2 \le i \le 5$)は $9^{i-1}$ 個溜まったら次のキューとマージする。 こうすると

  • $\sum_{i=1}^{4}45 \times 9^i \times \frac{Q}{9^{i+1}} = 20Q$

となり、間に合うようになる。

$8$ まで下げると逆に増えてしまう。見積もりをちゃんと定式化しないと、$9$ が谷という点がなかなか見つけづらい。(まぁ、実験による探索はできるが)


以下の実装では、何故か「2本のキューをマージして新しい列を生成する先のキューは、2本とは別の空のキューでないといけない」と勘違いしたまま通した。 (実際は前述の通り、ローテーションさせることでマージ対象のキュー自身にマージ結果を生成できる)

$Q1$ 以外のキューに、$E,S,M,L$ の4つの役割を割り当てる。
$E$ は空でマージ先として用意しておく。$S,M,L$ はこの順に要素数が多いキューとする。クエリ毎に役割は交替しうる。

$Q1$ の昇順が崩れたとき、パラメータ $r$ により、マージ先を分岐させる。$Q1$ の末尾を除いた列を $A$ とする。

  • $r(|A|+|S|) \lt |M|$ なら、$A$ と $S$ のマージ結果を $E$ に生成。$E,S←S,E$ に役割を振り直す
  • $r(|A|+|S|) \ge |M|, r(|A|+|S|+|M|) \lt |L|$ なら、$A,S,M$ のマージ結果を $E$ に生成。$E,M←M,E$ に役割を振り直す
  • $r(|A|+|S|+|M|) \ge |L|$ なら、$A,S,M,L$ のマージ結果を $E$ に生成。$E,L←L,E$ に役割を振り直す

この $r$ を、各時点での全体の要素数 $t$ を用いて $r=\dfrac{t^{1/3}}{2}$ とし、 他にも細かな最適化を施すと、降順に要素が与えられるという最悪っぽいケースでもギリギリ $10^5$ 以下となる。

Python3

programming_algorithm/contest_history/atcoder/2026/0809_arc226.txt · 最終更新: by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0