AtCoder Regular Contest 203 (Div. 2)A,B,C,D,E問題メモ

A - All Winners

問題文

  • 将棋の団体戦の大会に $N$ チームが参加しています。
    • 各チームは $M$ 人の選手からなります。
    • この大会は総当たり戦で、合計で $\frac{N(N-1)}{2}$ 試合が行われます。
    • 各試合ではそれぞれのチームの $M$ 人の選手同士がランダムにマッチングされて対局を行い、必ず一方が勝って一方が負けます。
  • 全ての試合が行われた後、各選手はちょうど $N-1$ 回対局を行ったことになりますが、全ての対局に勝った選手には全勝賞が与えられます。
  • 全勝賞を与えられる選手の人数としてありうる最大値を求めてください。
  • $1$ つの入力ファイルにつき、$T$ 個のテストケースを解いてください。

制約

  • $1 \leq T \leq 2 \times 10^5$
  • $2 \leq N \leq 10^9$
  • $1 \leq M \leq 10^9$
  • 入力される値は全て整数

解法

「チームで総当たり」するが、その中では「個人戦が $M$ 回」ある。
チームに対して総当たり表を描いても、ある個人が全試合を通して勝ったか負けたか、が微妙に追いづらい。

$N \times M$ のグリッド状に選手を並べて、それぞれに「全勝要員」「全敗要員」を割り振るとする。
1人の全勝要員を全勝させるためには、その人の所属以外のチームにそれぞれ1人、負ける人が必要。
1回でも負けた人は全勝できないため、他の全勝要員を全勝させるための相手として、なるべく負けをそこに集中させた方がよい。
(なんかこう書くと、勝敗を自由に操作できる闇のゲームマスターっぽい)

対称性があるのでとりあえず、Team1の選手1を全勝要員とする。
Team2~5の選手から1人(誰でもいいのでとりあえず選手1)が、全敗要員となる。

       Team1  Team2  Team3  Team4  Team5
選手1   ◎     ×     ×     ×     ×        ◎:全勝要員
選手2                                         ×:全敗要員
選手3
  :

このような図で表すと、問題は以下のようになる。(何か却ってややこしくなってる気もするが)

  • 各Teamから選手を1人ずつ選んで、その選手らを横に結ぶ線を引く。
    • 1本の線は「ある1人の全勝要員の試合履歴」を表し、$1$ 個の◎と $N-1$ 個の×を含む。
    • 同一チームの異なる◎は、その線上にある×が全て異なっていなくてはいけない。
      • でないと、同じ試合で同じ×が2回対局していることになる
    • 全体を通して、◎は $1$ 回、×は $N-1$ 回選べる。
  • 線をできるだけ多く引いてください。

すると、以下のように◎×を配置し、

       Team1  Team2  Team3  Team4  Team5
選手1   ◎     ◎     ◎     ◎     ◎
選手2   ×     ×     ×     ×     ×
  :

「1行目の◎を1個、2行目の×を $N-1$ 個通過する」線が $N$ 本引ける。
この配置は全敗要因がちゃんと全敗しているため、これ以上全勝要因を増やすことはできない。

$M$ が偶数なら、これを繰り返せばよくて、$N \times \frac{M}{2}$ となる。

$M$ が奇数なら、後1本だけ追加できる。

       Team1  Team2  Team3  Team4  Team5
選手1   ◎     ◎     ◎     ◎     ◎
選手2   ×     ×     ×     ×     ×
選手3   ◎     ◎     ◎     ◎     ◎
選手4   ×     ×     ×     ×     ×
選手5   ◎     ×     ×     ×     ×

最適である証明

Python3

B - Swap If Equal Sum

問題文

  • $0$ と $1$ からなる長さ $N$ の整数列 $A=(A_1,A_2,\dots,A_N),\; B=(B_1,B_2,\dots,B_N)$ が与えられます。
  • 数列 $A$ の $i$ 番目から $j$ 番目の連続部分列を $A[i,j]$ と表すことにします。
  • $A$ に対して、「区間が重なっておらず、総和が等しい2つの連続部分列をswapする操作」を何回でも行えます。
  • 形式的に言うと、
    • 以下の $2$ 条件を満たす $4$ 整数 $a,b,c,d$ を選ぶ。
      • $1 \leq a \leq b \lt c \leq d \leq N$
      • $\sum_{i=a}^{b}{A_i}=\sum_{i=c}^{d}{A_i}$
    • $A[a,b]$ と $A[c,d]$ を入れ替える。より厳密には、$A$ を、$A[1,a-1]$, $A[c,d]$, $A[b+1,c-1]$, $A[a,b]$, $A[d+1,N]$ の順に結合した数列に置き換える。
  • $A$ を $B$ に一致させられるかどうかを判定してください。
  • $1$ つの入力ファイルにつき、$T$ 個のテストケースを解いてください。

制約

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

解法

コーナーケース注意力勝負。

とりあえず、最初から $A=B$ ならYes、1の個数が異なるものはNoとして、自明なケースは除いておく。

手元で実験してみると、結構なんでも入れ替えられちゃう。
特に、'1'と、'01'や'10'を入れ替えれば0を好きな位置に移動できて、なんなりと好きな形にできる。

できないのはどういう時かというと、'1'が1個しかない時。1を含む区間を2つ取れない。
しかし、そういう場合でも、「区間和が0の区間」の入れ替えは可能なので、 1の左右に0があるときは '0'と'00'を操作すれば、1の左右の0の長さを自由に調整できる。

0010000  →  0001000
~  ~~

よって、「1が1個しかなく、$A$ または $B$ でその1が端に位置しているもの」はNoで、それ以外はYesとなる。

1が2個以上ある時に必ずできる証明

Python3

C - Destruction of Walls

問題文

  • 縦 $H$ 行、横 $W$ 列のグリッド状に部屋が並んでいます。
  • 上下左右に隣り合う部屋の間には壁がありますが、取り壊せば互いに移動できるようになります。
  • 以下の条件を満たすような $K$ 個の壁の組の選び方の総数を $998244353$ で割った余りを求めてください。
    • 選んだ壁をすべて取り壊すと、最も左上の部屋からいくつかの部屋を経由して最も右下の部屋に移動することができる。
  • $1$ つの入力ファイルにつき、$T$ 個のテストケースを解いてください。

制約

  • $1 \leq T \leq 2 \times 10^5$
  • $2 \leq H \leq 2 \times 10^5$
  • $2 \leq W \leq 2 \times 10^5$
  • $\boldsymbol{0 \leq K \leq H+W}$
  • 入力される値は全て整数

解法

重要な制約を太字で書いてくれている親切設計。

左上から右下まで移動するのに最低 $H+W-2$ 個の壁は取り壊さないといけないので、それ未満は $0$。
必要最小数から余るのが、0個か、1個か、2個か、という問題となる。

0個の場合は最短距離の経路数と一致するので、${}_{H+W-2}C_{H-1}$ となる。

1個の場合は、余分な壁 $(H-1)W + H(W-1) - (H+W-2)$ 個から追加で1個選べばよい。
これによって重複が発生したりすることはない。

問題は2個の場合である。これがこの問題の本質となる。

最短経路で到達可能

1個の場合と同様、余分な壁から追加で2個選ぶ。

ただしその際、以下のように2×2の正方形状に選ばれると、2通りの最短経路から同じ選び方が重複して数えられてしまう。

┼  ┼─┼─┼─┼
│      →  │  │
┼─┼↓┼↓┼─┼
│  │  →      │
┼─┼─┼─┼  ┼

このような選び方の個数は、正方形状に選ぶのを「↘への斜め移動」と見なし、 「縦移動 $H-2$ 回」「横移動 $W-2$ 回」「斜め移動 $1$ 回」を並べると考えられる。

  • $\displaystyle \frac{(H+W-3)!}{(H-2)!(W-2)!}$

これを全体から引けばよい。

遠回りする

こんなやつ

┼  ┼─┼─┼─┼
│      │  →  │
┼─┼↓┼↑┼↓┼
│  │  →  │  │
┼─┼─┼─┼  ┼

$H+W$ 個の壁全てを使って、1マス分だけ、上または左に戻る経路を構築できる。

上に戻る場合、必ずその前後は横移動(→↑→ という移動)となる。
これを1セットと考える。

先ほどの正方形のやつと同じように考えられるかと思いきや、 この移動は「縦移動を1つもおこなっていない状態」「全ての縦移動をおこなった後」は、 グリッド外に出るような軌跡となってしまうため、選ぶことができない。

よって、ひとまず縦移動と混ぜてパターン数を数え、 後から最初と最後以外の縦移動のどれか1箇所を置き換える、という捉え方をする。

  • $\displaystyle \frac{(H+W-2)!}{(H+1)!(W-3)!} \times (H-1)$

左に戻る場合も、同様に↓←↓を1セットとして考えられる。

Python3

D - Insert XOR

問題文

  • $0$ と $1$ からなる長さ $N$ の整数列 $A=(A_1,A_2,\dots,A_N)$ があります。
  • $Q$ 個のクエリが与えられます。$q$ 番目のクエリは以下のようなものです。
    • $1$ 以上 $N$ 以下の整数 $i_q$ が与えられる。$A_{i_q}$ が $0$ なら $1$ に、$1$ なら $0$ に変更する。
  • 各クエリを処理するたびに、以下の問題の答えを求めてください。
    • $0$ と $1$ からなる数列 $B=(B_1,B_2,\dots,B_{|B|})$ のうち以下の条件を満たすものを考えます。
      • $B$ に対して以下の操作を好きな回数行って、数列 $A$ と一致させることができる。
        • $1$ 以上 $|B|-1$ 以下の整数 $i$ を選ぶ。
        • $B_i$ と $B_{i+1}$ の間に $B_i\oplus B_{i+1}$ を挿入する。
    • $|B|$ として考えられる値の最小値を求めてください。条件を満たす $B$ は必ず存在することが証明できます。

制約

  • $3 \leq N \leq 2 \times 10^5$
  • $0 \leq A_i \leq 1$
  • $1 \leq Q \leq 5 \times 10^5$
  • $1 \leq i_q \leq N$
  • 入力される値は全て整数

解法

セグメント木。
公式Editorial のように、logがつかないより計算量の良い解法でも解けるが、 まぁセグ木でも解けそうな見た目をしているので、セグ木解法を考える。

まず、$B$ からの操作がどのようになるか考えると、

  • 00 に操作すると、いくらでも 0 を増やせる
  • 01, 10 に操作すると、1 を増やせる
  • 11 に操作すると、間に1つだけ 0 を挿入した後、両側に1を増やせる

逆に $A$ をどこまで縮められるか、という観点で考えると、

0 が2個以上連続した部分は、00にまで縮められる
  000...00→00

0 が1個のみ連続し両端に1がある部分は、0を消せる
  111011→11111

1 が2個以上連続しどちらかに0がある部分は、1にまで縮められる
  01111100→0100

0 に挟まれた 1 を消したり、1 に挟まれた 00 を消したりはできない。

よって、$B$ として最短の文字列は、00 と 1 が繰り返される形となる。

000011101111000111010101110
~~~~________~~~___________~

0010010    端の1個だけの0はそのまま残る
~~_~~_~

例外として、

  • $A$ の全てが 1 の場合は、0がないと1を増やすことができないため、$B$ は $A$ から1文字も縮められない。
  • $A$ に 00 が含まれない場合は、$B$ は 11(1は最低2つ残さないといけない)

以上を整理した結果、セグ木には以下を載せる。

  • $(左端の状態, 右端の状態, 区間内で縮められる文字数)$

「0が3つ以上続いているなど、その場で縮められるとわかっている部分は、貪欲に縮める」方針とする。
各ノードが表す $A_i$ の区間を、00と1の繰り返し(と端の0)になるまで縮めた場合に省略できる文字数を計算していく。
貪欲に縮めた結果が正しくならない上記の例外の2ケースは、別の方法で判定することにする。

左端として考えられるのは、以下の4通りとなる。

  • 0(1文字からなる区間)
  • 1…
  • 00…
  • 01…

右端も同様に、4通りの状態があれば区別できる。

ノード $X$ と $Y$ をマージするとき、$X$ の右端と $Y$ の左端を見て、16通りについて適切に処理する。
たとえば […10] と [1…] の結合では、1文字の0を除去し、その後11を1にできるので、計2文字、縮められることになる。
16通りの実装というと面倒そうだが、処理はほとんど一緒で、何文字縮められるかだけの違いとなる。

00と1は消えないので、'0'の1文字の場合以外は、結合により左端が変化したとしても右端の形が変化すること(または逆)はない。

例外については、

  • $A$ が全て'1'かどうかを調べられればよい。総和を管理しておき、総和 $=N$ となったかどうかなどで調べられる。その場合、答えは $N$
  • $A$ 全体で縮められる文字数が $N-1$ になった場合は、'1'まで縮めすぎているということなので、答えは $2$

それ以外の場合は、$N-(A全体で縮められる文字数)$ が答えとなる。

Python3

E - Tile Grid with One Hole

問題文

  • 縦 $H$ 行、横 $W$ 列のグリッドがあり、$(r,c)$ のマスだけに穴が空いています。
  • 縦 $1$ 行、横 $L$ 列のタイルを横長タイル、縦 $L$ 行、横 $1$ 列のタイルを縦長タイルと呼ぶことにします。
  • 穴が空いていないマス全体を、横長タイル $N$ 枚と縦長タイル $M$ 枚を回転させないまま使う敷き詰め方が存在するかを判定し、存在するなら敷き詰め方も示してください。
  • $1$ つの入力ファイルにつき、$T$ 個のテストケースを解いてください。

制約

  • $1 \leq T \leq 5$
  • $1 \leq H \leq 1000$
  • $1 \leq W \leq 1000$
  • $2 \leq H \times W$
  • $2 \leq L \leq 1000$
  • $0 \leq N$
  • $0 \leq M$
  • $1 \leq r \leq H$
  • $1 \leq c \leq W$
  • $H \times W=L \times (N+M)+1$
  • 全てのテストケースにおける $N+M$ の総和は $6\times 10^5$ 以下
  • 入力される値は全て整数

解法

こういうの、どう見つければ&これで全てだとどう確信すればよいか全然わかんない。
(まぁそれが難しいからこそ、実装自体は簡単でもARCのラストに置かれているのだろうが)

愚直を書いてエスパーできるかと思いきや、 全探索のパターン数が多すぎて、ちょっと盤面を広げると全然終わらない。

ただ、ランダムな入力だと全然見つからないので、 相当、条件が揃ったときでないと、敷き詰め方は存在しないのだろうという予測は立つ。

理詰めでの解き方

行・列を 0-indexed とする。
個数制限 $N,M$ は一旦無視して、$H,W,L$ および穴の位置 $r,c$ に求められる条件を考える。

このような幅1のタイル問題の証明でたまにある考え方として、盤面に $(i+j) \mod {L}$ を書き込んでいく。

L=4
012301230
123012301
230123012
301230123
012301230

この時、1枚のパネルは縦でも横でも $0~L-1$ をちょうど1つずつ含む、という性質があり、上手く利用できる場合がある。

このまま考えを進めてもいいのだが、今回の問題では少し変えて以下のようにすると、 「穴の位置の条件」もあわせて求められる。

  • $i$ 行目に $i \mod{L}$ を置く
000000000
111111111
222222222
333333333
000000000

1枚のタイルは、「1つの数字を $L$ 個含む(横向き)」か「$0~L-1$ を1つずつ含む(縦向き)」
つまり、上手く覆える方法があったとき、「ある数字がタイルに覆われている回数 $\mod{L}$」は全ての数字で等しくなる。

穴を含めて考えると、盤面はどれか1つの数字だけが $\mod{L}$ で他より1だけ多い必要がある。
より条件を緩めて「どれか1つの数字だけ、行としての出現回数が異なっている」と考えると、これは以下の2通りだけに限られる。

  • $H \equiv 1 \mod{L}$
    • この時、$HW \equiv 1 \mod{L}$ となるためには、$W \equiv 1 \mod{L}$
    • 1つだけ多い数字は $0$。つまり、$r \equiv 0 \mod{L}$
  • $H \equiv L-1 \mod{L}$
    • この時、$HW \equiv 1 \mod{L}$ となるためには、$W \equiv L-1 \mod{L}$
    • 1つだけ多い数字は $L-1$。つまり、$r \equiv L-1 \mod{L}$

同様の理論を列方向でもおこなうと $c$ についても同じことが言える。

これらを合わせて、敷き詰め可能な必要条件は以下の2通りとなる。

  • ① $(H,W) \equiv (1,1) \mod{L}$ かつ $(r,c) \equiv (0,0) \mod{L}$
  • ② $(H,W) \equiv (L-1,L-1) \mod{L}$ かつ $(r,c) \equiv (L-1,L-1) \mod{L}$

それぞれについて、可能な $N,M$ の条件、および敷き詰め方を考える。

$H \equiv 1 \mod{L}$ より、穴以外の列は、どこかに横向きのタイルを1枚は置く必要がある。
つまり、$\frac{W-1}{L}$ 枚は横向きのタイルが必要。
同様に、$\frac{H-1}{L}$ 枚は縦向きが必要。
このタイルをとりあえず適当に置く。
置いた後に残っている横向き・縦向きタイルの枚数を $N', M'$ とする。

各行における残りのマス数は、どの行も $L$ の倍数となる。
先ほどと同様、$i$ 行目の残りマスに $i$ を書き込む。$i$ が書き込まれる総回数は、いずれも $L$ の倍数となる。

000000│00
111111│11
222222│22
333333│33
0000×0000
1111│────
2222│2222
3333│3333
────│0000

(繰り返しになるが)横のタイルは1つの数字を $L$ 回、縦のタイルは $0~L-1$ を1回ずつ覆う。
つまり、各数字が覆われる総回数を $L$ の倍数とするためには、縦のタイルは $L$ の倍数回、使わないといけない。
よって、$M' \equiv 0 \mod{L}$ が必要条件となる。

列方向に対しても同様で、$N' \equiv 0 \mod{L}$ が必要となる。

この2条件があれば以下のように構築できる。

  • 穴の行に、$\frac{W-1}{L}$ 枚の横向きのタイルを置く
  • 穴の列に、$\frac{H-1}{L}$ 枚の縦向きのタイルを置く
  • 残りはいくつかの $L \times L$ のブロックに分けられる。
    • ブロック毎に、$N',M'$ の残数に応じて横 $L$ 枚または縦 $L$ 枚で正方形を作って埋めていく
      │      
 LxL  │  LxL      LxL: その領域をLxLのブロックに
      │                分割可能であることを示す
───×───
      │      
 LxL  │  LxL
      │

穴以外の列には、$L-1$ 枚(mod L)の横向きタイルが必要。穴の列には、$L-2$ 枚(mod L)の横向きタイルが必要。
左端から、列に必要な枚数の横向きタイルを敷き詰めていくと自由度がなく、$c \equiv L-1 \mod{L}$ とあわせて、以下のような形に決まる。
(各タイルは上下に平行移動してもよいとする)

────────                  L=4
────────                  縦のタイルだけではどうしても覆えない、
────────                  横向きタイルの必要数 と 敷き詰め方の一例
              ×
              ────────
              ────────
              ────────

この時、$N \ge \frac{W+1}{L}(L-1)$ である必要がある。必要なタイルを敷いた残りを $N' = N - \frac{W+1}{L}(L-1)$ とする。

縦向きタイルと $M$ についても同様に、必要最低数が決まる。$M' = M - \frac{H+1}{L}(L-1)$ とする。

必要な縦横タイルを敷き終えると、まだタイルが敷かれていない残りのマス数は、行・列ともに全て $L$ の倍数となる。

①の時と同様の $0~L-1$ を書き込んでいく証明法で、$N', M'$ は $L$ の倍数である必要があることがわかる。
またその時に、$L \times L$ ブロックに分けて構築する方法があることを示せる。

                │││
       LxL      │││
                │││
                │││  LxL
────────│││
────────│││
────────│││
        │││×│││
        │││────────
        │││────────
   LxL  │││────────
        │││
        │││       LxL
        │││
        │││

Python3

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