AtCoder Regular Contest-- 224 B,C,D,E,F問題メモ

B - Adjacent Tiles

問題文

  • 同じ大きさの正方形のタイル $N$ 枚を、平面上に重ならないように配置します。
  • このとき、一辺を完全に共有している相異なるタイルのペアの個数は最大でいくつになりますか?
    • ただし、タイルのペア $(a,b)$ が一辺を完全に共有するとは、 $a$ のある辺と $b$ のある辺が完全に一致することをいいます。
  • $T$ 個のテストケースが与えられるので、それぞれについて答えを求めてください。

制約

  • $1 \le T \le 2 \times 10^5$
  • $1 \le N \le 10^{18}$
  • 入力はすべて整数

解法

こうだろうという直感が概ね正解ではあるが、ちゃんと証明しようと思うと丁寧な思考が必要。

$\left \lfloor \sqrt{N} \right \rfloor$ 四方の正方形に置いて、 余った分はもう1つ外側の行・列にL字に追加していく、という方法が1つの正解となる。

N=11      N=14
■■■■  ■■■■
■■■■  ■■■■
■■■□  ■■■■
          □□■■

まぁ直感的に、長方形が強そうというのは分かる。外周以外の全タイルが4辺全てを共有できるので。
同じ面積の長方形なら2辺の差が小さいほど外周が短くなることから連想すると、この場合も、同じ長方形に並べるのでも正方形に近い方がより強そう。

全長方形の辺 $4N$ 個から、ペアにできない辺の最小化を考える。
ペアにできない辺数を $m$ とすると、答えは $\dfrac{4N-m}{2}$ となる。

$m$ は、図形に穴が無ければ外周の長さと一致する。
さらに凹みが無ければ、その図形の外周はそれをすっぽり覆う長方形と一致する。
凹みや穴があれば、明らかに外周はそれより増える。

よって、すっぽり覆う長方形がなるべく正方形に近くなるように置けば、$m$ を最小化できる。

Python3

C - Ascending Labels

問題文

  • $N$ 頂点 $M$ 辺の連結な単純無向グラフが与えられます。
  • 頂点には $1,2,\ldots,N$ の番号が付けられており、$i$ 個目の辺は頂点 $U_i$ と頂点 $V_i$ を結びます。
  • 以下の条件をすべて満たす整数列 $A=(A_1,A_2,\ldots,A_N)$ を $1$ つ構築してください。
    • すべての頂点 $v$ について、$0 \le A_v \le N$ である。
    • $A_1=0$ である。
    • 頂点 $1$ 以外のすべての頂点 $v$ について、$v$ に隣接する頂点 $w$ のうち $A_w=A_v-1$ を満たすものがちょうど $1$ つ存在する。
  • なお、本問題の制約下で、上記の条件をすべて満たす整数列が少なくとも $1$ つ存在することが証明できます。また、条件を満たす整数列が複数存在する場合、どれを出力しても正答とみなされます。
  • $T$ 個のテストケースが与えられるので、それぞれについて答えを求めてください。

制約

  • $1 \le T \le 3 \times 10^4$
  • $1 \le N \le 3 \times 10^5$
  • $N-1 \le M \le 3 \times 10^5$
  • $1 \le U_i \lt V_i \le N$
  • $i \neq j$ ならば $(U_i,V_i) \neq (U_j,V_j)$
  • 与えられるグラフは連結
  • ひとつの入力における $N$ の総和は $3 \times 10^5$ 以下
  • ひとつの入力における $M$ の総和は $3 \times 10^5$ 以下
  • 入力はすべて整数

解法

DFS木を構築し、頂点 $1$ からの距離を $A_v$ とすればよい。

基本、(DFS木で無くても)何らかの全域木で頂点 $1$ からの距離を $A_v$ とすれば、 「★ $v$ に隣接する頂点 $w$ のうち $A_w=A_v-1$ を満たすものが存在する」ようにはできる。 (距離 $d$ にたどり着くには $d-1$ を経由しなければならないのは当然)

問題は、全域木に元の辺を戻して考えたとき、★が「ちょうど $1$ つ」になることを保証できない点。

①
↓↘      ↓:全域木の辺
②  ③    ::全域木以外の辺
↓↘:
④  ⑤    A2=A3=1, A5=2 となるのに、⑤が②③の両方と繋がってしまっている

DFS木なら、一度訪れた頂点と繋がっている未訪問頂点は探索され尽くすので、 使われない辺は、必ずDFS木での「祖先と子孫を結ぶ辺」となる。別の部分木同士の頂点が結ばれることは無い。

よって、DFS木に使われていない辺同士が結ぶ2頂点は $|A_w-A_v| \ge 2$ となるので、木の親の他に★が増えることは無い。

Python3

D - Angst for All Pairs

問題文

  • $N$ 枚のカードがあり、$1$ から $N$ までの番号が付けられています。はじめはどのカードも何も書かれていません。
  • あなたはそれぞれのカードに $0$ 個以上の正整数を書き込むことができます。
  • 正整数 $k$ を $1$ 回書き込むときにかかるコストは、$k$ の十進表記での桁数に等しいです。
  • 以下の条件を満たすことが可能か判定し、可能であれば必要な総コストの最小値を、不可能であれば $-1$ を出力してください。
    • $1 \leq x \lt y \leq K$ を満たすどの正整数組 $(x,y)$ についても、そのうち片方だけを含むカードが存在する。
  • $T$ 個のテストケースが与えられるので、それぞれについて答えを求めてください。

制約

  • $1 \leq T \leq 10^5$
  • $1 \leq N \leq 10^6$
  • $2 \leq K \leq 10^6$
  • ひとつの入力における $N$ の総和は $10^6$ 以下
  • ひとつの入力における $K$ の総和は $10^6$ 以下
  • 入力はすべて整数

解法

整数 $x$ を書き込むカードの集合を $S_x \subset \{1,2,...,N\}$ とする。
もし $S_x$ と $S_y$ が一致すれば、「$x,y$ の一方のみが書かれたカード」は存在しない。
逆に1つでも異なればよいので、$N$ 枚のカードでは $1~2^N$ の範囲の整数組を区別できることになる。

まず $K \gt 2^N$ なら不可能、そうでなければ可能となる。以下、可能とする。

$x$ の桁数を $k_x$ とすると、$k_x|S_x|$ が $x$ を書き込む総コストとなる。 $k_x$ が大きい方から、なるべく $|S_x|$ が小さいような集合を与えればよい。

S_{K}     = {}  (空集合)
S_{K-1}   = {1}
S_{K-2}   = {2}
 :
S_{K-N}   = {N}
S_{K-N-1} = {1,2}
S_{K-N-2} = {1,3}
 :

のように、大きい整数から、小さい集合を割り当てていけばよい。

実装としてはいろいろあるが、

  • 左辺側: $1~K$ の $(桁数, その桁数となる値の個数)$ を、桁数の降順に並べた列
    • $K \le 10^6$ なので、高々 $7$ 要素
  • 右辺側: $(要素数, その要素数となる集合の個数)$ を、要素数の昇順に並べた列
    • 集合の個数は二項係数で計算できる。
    • 要素数の小さい方から並べ、累計が $K$ 個を超えたら打ち切ってよい。だいたい $20$ もあれば超える。

この2つを、先頭から同個数分だけマッチングさせていけばよい。
右辺側は、枝刈りせず例えば要素数 $N$ まで毎ケース作るとTLEしてしまうので、枝刈りは必須。

Python3

E - ABC|AB|A

問題文

  • A, B, C からなる文字列 $S$ が与えられます。
  • 以下の操作を $0$ 回以上何回でも行えます。
    • $S$ から A または AB または ABC である部分文字列 (連続部分列) を $1$ つ選択して削除する。残った文字は順序を保って連結される。
  • 最終的な $S$ の長さとして達成可能な最小値を求めてください。
  • $T$ 個のテストケースが与えられるので、それぞれについて答えを求めてください。

制約

  • $T$ は $1$ 以上 $10^5$ 以下の整数
  • $S$ は A, B, C からなる長さ $1$ 以上 $10^6$ 以下の文字列
  • ひとつの入力における $|S|$ の総和は $10^6$ 以下

解法

'AABCBC' など、間を削除した結果、前後の 'A' と 'BC' が繋がって新たに削除可能になる、ということもある。
このようなケースはスタックを用いて管理し、削除可能になったら pop していくと上手く管理できる。

ただ、先頭から溜めていくと、例えば 'AB' まで溜まったとして、これを即座に削除していいのか、 後から 'C' が繋がって 'ABC' として削除できるのか、その時点で確定できない。

逆から考えると見通しが良くなる。

'CBA'|'BA'|'A' を削除できるとして、逆からスタックに溜めていくと、 'BA' と溜まった時点で、もうこれは 'BA' 以外の何者にも発展することはないので削除してよい。
('A' のみ削除し、残った 'B' に後から別の 'A' が繋がって 'BA' として削除、という操作もできなくは無いが、 それは現時点で 'BA' として削除し、別の 'A' は単独で削除するものと組み替えて、損しない)

'A' が来るたび、以下のようにすればよい。

  • スタック末尾が 'CB' なら 'CBA' として削除(2つpop)
  • スタック末尾が 'B' なら 'BA' として削除(1つpop)
  • スタック末尾がそれ以外なら 'A' として削除

それ以外はスタック末尾に追加していき、最終的なスタック長が答えとなる。

Python3

F - AND/OR

問題文

  • 長さ $N$ の非負整数列 $A=(A_1,A_2,\dots,A_N)$ と整数 $K$ が与えられます。
  • はじめ、$x=0$ です。$i=1,2,\dots,N$ の順に、以下の $2$ つの操作のうち一方を選んで行います。
    • 操作 $1$ : $x$ を $x$ ${\rm AND}$ $A_i$ に置き換える。
    • 操作 $2$ : $x$ を $x$ ${\rm OR}$ $A_i$ に置き換える。
  • ただし、操作 $2$ を選ぶ回数は全体で $K$ 回以下でなければなりません。
  • 全ての操作が終了した時点の $x$ として達成可能な最大値を $M$ とします。
  • 最終的な $x$ が $M$ となる操作列の個数を $998244353$ で割った余りを求めてください。
  • ただし、$2$ つの操作列は、ある整数 $j$ ($1 \le j \le N$) について $j$ 回目に選んだ操作が異なるとき、またそのときに限り区別されます。
  • $T$ 個のテストケースが与えられるので、それぞれについて答えを求めてください。

制約

  • $1 \le T \le 10^4$
  • $1 \le K \le N \le 2 \times 10^5$
  • $0 \le A_i \lt 2^{60}$
  • ひとつの入力における $N$ の総和は $2 \times 10^5$ 以下
  • 入力はすべて整数

解法

落ち着いて考えれば難しくはない。

末尾 $K$ 要素を OR した結果を $m$ とすると、達成可能な最大値 $M=m$ となる。

略証

$m$ で立っている各 bit に対し、末尾から見たときにはじめて '1' が現れる index を求め、 その中で最も小さいものを $l$ とする。

 i  A(2進表記)
    1234567 桁目
 :
 8  0110010  ← 3,6桁目の'1'が、末尾から見てはじめて i=8 で現れ、これが最小
 9  1100100     よって l=8 となる。
10  1000101
-----------
 m  1110111

この時、$l$ より後の $i$ では、必ず OR 操作が必要となる。 AND にすると、$m$ で立てなければならないはずの bit が '0' になってしまうので。

$l$ 自身は、OR と AND の両方の可能性がある。

OR にしたら、$l$ より前はどう操作しても結果が $m$ になることが保証される。
$l$ 以降の OR 操作分を除いた、$l$ より前に使える OR 操作の回数を $r$ として $\displaystyle \sum_{k=0}^{r} \binom{l-1}{k}$ があり得る操作の数となる。

AND にした場合、再帰的に同じ構造の問題に帰着できる。

  • $N←l-1$
  • $K←K-$($l$ より後に必要な OR 操作分)
  • $m$ は、$l$ ではじめて '1' が現れたbitの集合とする。
    • 上例の場合、3,6 桁目は $l$ ではじめて立つので、$m←0010010$

$i=l-1$ の操作終了時点で 3,6 桁目を '1' にできれば、$l$ をAND、それ以降をORにすることで、$M$ を達成できる。

よって、新しい $N,K,m$ で同様に

  • $l$ を求める。
    • ただし、今度は必ずしも存在するわけではない。$m$ で立っている bit のうち1つでも、末尾 $K$ 個内に '1' が立っているのが無いものがある場合、そこで終了。
  • $l$ をORにした場合は確定。$l-1$ 以前の決め方を答えに加算
  • ANDにした場合は再帰的に同じ問題に帰着する

ということを繰り返せばよい。$N=0$ または $K=0$ または $m=0$ になったら終了。

後は、$l$ をORにした時、$\displaystyle \sum_{k=0}^{r} \binom{l-1}{k}$ を求める部分。
愚直にやってしまうと、1回につき $O(r) \simeq O(K)$ かかるので、 $K$ がなかなか減らないまま再帰が深くなる場合に $O(NK)$ の計算量を要してしまう。

二項係数の累積和 $\displaystyle f(n,r)=\sum_{k=0}^{r} \binom{n}{k}$ を計算する時のテクニックとして、 $f(n,r)$ の結果から $f(n-1,r)$ や $f(n,r-1)$ を $O(1)$ で計算できることを活かせば、$O(N+K)$ に抑えられる。

Python3

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