CodeQUEEN 2026 決勝 E,F,G,H問題メモ

E - 絶品のバイオリン

問題文

  • プリンセスの高橋さんは、バイオリンの練習をしています。
  • 高橋さんのバイオリンには $N$ 本の弦があります。
  • $i$ 番目の弦を使うと、周波数が $L_i$ 以上 $R_i$ 以下の実数である任意の音を出すことができます。
  • 高橋さんは、お腹が空いたので弦を $0$ 本以上選んで食べることにしました。食べた弦は無くなります。
  • ただし、バイオリンを壊したくはないため、以下の条件は守らなくてはいけません。
    • 弦を食べる前に出すことのできたすべての周波数の音は、弦を食べた後にも出すことができる
  • 食べることのできる弦の本数の最大値を求めてください。

制約

  • $1 \le N \le 2 \times 10 ^ 5$
  • $1 \le L_i \le R_i \le 10^9$
  • 入力はすべて整数である

解法

以下の問題の答えが $a$ だとすれば、元の問題の答えは $N-a$ である。

  • $[l,r]$ の区間がいくつかある。指定された対象区間(=元の区間で覆える区間)をくまなく覆うのに必要な最小の区間数は?

ただし、対象区間が必ずしも1つの連続した区間でなく、飛び飛びの可能性もある。 以下のようにすると、最短経路問題に落とし込める。

  • 各弦の端点の座標 $l,r$ を座標圧縮し、$0,1,...,n$ に変換しておく。(以下、$l,r$ は変換後を表す)
  • 各弦につき、$l→r$ にコスト $1$ の辺を張る。
  • 各 $i$ につき、$i→i-1$ にコスト $0$ の辺を張る。
  • 元の弦で表現できない区間を $(i,i+1)$ として、$i→i+1$ にコスト $0$ の辺を張る。
    • ※座標圧縮しているので長さは必ず $1$

これで、$0→n$ へのコストが、最低限必要な弦の本数となる。

ただし、これは細かな落とし穴がある。(親切なことに入力例3で気付けるようになっている)
$[l,r]=[40,40]$ のように $l=r$ の弦に対して、 周波数 $40$ は「元の弦で出すことのできたすべての周波数」に含まれるので、残す必要がある。

しかし、上記のアルゴリズムではそれが無視され、不要と判断されてしまう。 半開区間 $[l,r)$ として扱われるので、$l=r$ は実質的な長さを持たないためである。

長さを持たせるといい。座標圧縮前に以下のように変換すると正しく動作するようになる。

  • $l←2l$
  • $r←2r+1$

Python3

F - ピアノの練習

問題文

  • プリンセスの高橋さんは、ピアノの練習をしています。
  • ピアノには $N$ 個の鍵盤があり、左から順に $1,2,\ldots,N$ と番号が付いています。
  • 高橋さんには $A$ 本の腕があり、それぞれの腕には $B$ 本の指があります。各指は高々 $1$ 個の鍵盤を押すことができます。
    • ただし、同じ腕にある指で押すどの $2$ つの鍵盤についても、その番号の差は $D$ 以下でなければなりません。
  • $N$ 個の鍵盤から異なる $K$ 個を選ぶ選び方であって、選んだすべての鍵盤を同時に押すことのできるものの個数を $998244353$ で割った余りを求めてください。
  • ただし、どの腕・どの指を使うかが異なっていても、選んだ鍵盤が同じなら同じ選び方とみなします。

制約

  • $2 \le N \le 100$
  • $1 \le K \le N$
  • $1 \le A,B \le 10$
  • $1 \le D \le N-1$
  • 入力はすべて整数である

解法

次元の多いDP。やることは素直だが、遷移を落ち着いて考えないとこんがらがる。

とりあえず、複数の腕・指の押し方ができる鍵盤配置を重複して数えないよう、以下のように指を割り当てるルールを作る。

  • 同じ腕で押さえられる限り、同じ腕で押さえる。

つまり、左の鍵盤から押す指を決めていくとして、 腕 $a$ の最も左で押した鍵盤を $i$ とすると、腕 $a+1$ に切り替えるのは、以下のいずれかのみとする。

  • $i+D$ までに $b$ 本の指を使い切り、次の鍵盤の押す指を決める場合
  • $b$ 本の指は使い切っていないが、$i+D+1$ 以降の鍵盤を押す指を決める場合

これで、「指の押さえ方」と「答えとして数えるもの」が1対1対応するようになった。

以下のDPをする。1本の腕による押さえ方の情報を前計算しておいて、腕単位で遷移する。

  • $\mathrm{DP}[i,j,u]:=$
    • $i$ 個($i \le N$)の鍵盤から $j$ 個($j \le K$)押さえるうち、腕を $u$ 本使っているような方法の個数
    • ただし、$i$ 個の並びの左端は必ず押さえている。
    • 右端は、
      • $j=K$ なら必ず押さえている。
      • $j \lt K$ なら押さえていなくてもよい。
        • ただし直前の腕が $b$ 本未満しか指を使っていない場合、直前に使った腕の左端は $i-D-1$ 以下である。

これは、

  • $\mathrm{pre}[i,j]:= i$ 個($1 \le i \le D+1$)の鍵盤を、左端と右端は必ず使って、$j$ 個($j \le b$)の鍵盤を押さえる方法の個数

などの事前計算により遷移できる。

Python3

G - きみの愛馬は?

問題文

  • プリンセスの高橋さんは乗馬をしようとしましたが、間違えて競馬場に来てしまいました。
  • 競馬場では、$N$ 頭の馬がレースに出走します。馬には、単勝での人気が高い順に $1,2,\ldots,N$ の番号が付いています。
  • $N$ 頭の馬から異なる $K$ 頭を選び、その番号を昇順に並べた列 $(a_1,a_2,\ldots,a_K)$ を考えます。このような列 $\displaystyle\binom{N}{K}$ 個に、 $1$ 位から $\displaystyle\binom{N}{K}$ 位までの相異なる順位を付けます。
  • 順位の付け方は、次の条件を満たさなければなりません。
    • 異なる $2$ つの列 $a=(a_1,a_2,\ldots,a_K),~ b=(b_1,b_2,\ldots,b_K)$ が、すべての $i\ (1\le i\le K)$ について $a_i\le b_i$ を満たすならば、$a$ の順位は $b$ の順位よりも小さい。
  • 条件を満たすすべての順位の付け方を考えます。与えられた列 $(x_1,x_2,\ldots,x_K)$ の順位としてあり得る最小値と最大値を求め、それぞれを $998244353$ で割った余りを出力してください。

制約

  • $1 \le K \le N \le 10^9$
  • $K \le 300$
  • $1 \le x_1 \lt x_2 \lt \cdots \lt x_K\le N$
  • 入力はすべて整数である

解法

要は、「$(x_1,x_2,...,x_K)$ より“小さい”選び方は何通りありますか?」という問題となる。

(自身も含め)$k$ 個あったとしたら、順位の最小値は $k$ となる。 $x_1←N+1-x_1$ のように反転すれば、同じアルゴリズムで最大値の方も求められる。

同じ値を選んでもいいよう、$x$ を広義単調増加に変換する。index も便宜上、$0$ 始まりとする。

  • $(x_0,x_1,...,x_{K-1})←(x_1-1,x_2-2,...,x_K-K)$

$0~N-K$ の範囲の値を使った広義単調増加な数列 $(y_0,...,y_{K-1})$ であって、 全ての $i$ で $y_i \le x_i$ であるものの個数を数えたい。

これは、以下の経路数え上げ問題に落とし込める。

  • $(K+1) \times (x_K+1)$ グリッドがあります。左下が $(0,0)$、右上が $(K,x_K)$ です。
  • 各 $i=0,...,K-1$ につき、$(i,x_i+1)$ に障害物があります。
  • 右か上のみに移動して、左下から右上まで、障害物を通らずに移動する経路数を数えてください。

(問題を解く上で復元する必要は無いが)ある経路に対し、「$i$ 列目から $i+1$ 列目に移る時の高さ」を $h_i$ として、 $(h_0,h_1,...,h_{K-1})$ が $y$ の1つに対応する。

この問題は、障害物を何個踏んでしまったかの偶奇で包除原理DPをすることで、二項係数の事前計算を除き $O(K^2)$ で解ける。

ただ、今回の問題では $N$ が大きく階乗の事前計算ができないので、二項係数はその都度計算することにすると、$O(K^3)$ となる。

Python3

H - 迷子の森

問題文

  • プリンセスの高橋さんは、森の中で迷子になってしまいました。
  • 森には $N$ 個の広場と $M$ 本の道があります。
    • 広場には $1$ から $N$ までの番号が付いています。
    • 道 $i$ は広場 $a_i$ と広場 $b_i$ を双方向に結んでおり、幅は $c_i$、長さは $d_i$ です。
    • グラフは連結です。
  • 森には $K$ 匹の動物がいます。動物 $j$ は、はじめ広場 $v_j$ にいて、大きさは $x_j$ です。
    • 大きさが $x$ の動物は、幅が $x$ 以上の道だけを通ることができます。
  • 高橋さんは、はじめ広場 $1$ にいて、動物には乗っていません。高橋さんは次の行動を好きな回数行えます。
    • 動物に乗っていないとき、道を $1$ 本選んで歩いて移動する。このとき、歩行距離はその道の長さだけ増える。
    • 動物に乗っていないとき、同じ広場にいる動物に乗る。
    • 動物に乗っているとき、その動物が通れる道を $1$ 本選び、動物とともに移動する。このとき、歩行距離は増えない。
    • 動物に乗っているとき、その動物から降りる。動物はその広場に残る。
  • 高橋さんは道の幅によらず、どの道でも歩くことができます。また、道の途中で止まったり、動物に乗り降りしたりすることはできません。動物は、高橋さんが乗って移動するとき以外には移動しません。
  • 広場 $N$ に到達するまでの歩行距離の最小値を求めてください。

制約

  • $2 \le N \le 10^5$
  • $N-1 \le M \le 10^5$
  • $1 \le K \le 10^5$
  • $1 \le a_i \lt b_i\le N$
  • $1 \le c_i,d_i\le 10^9$
  • $1 \le v_j \le N$
  • $1 \le x_j \le 10^9$
  • 与えられるグラフは連結である
  • 入力はすべて整数である

解法

大きさ $x$ の動物のいる頂点から、その動物に乗って行ける範囲の頂点に、コスト $0$ の辺が張れればいい。

しかし $K$ 頭の動物に対し愚直に張ったら当然、$O(NK)$ となるのでTLE&MLE。

以下のようにするといい。「マージ過程を表す木」と呼ばれる。

  • 元の $N$ 頂点の他に、以下のように $N-1$ 個の頂点を追加する。
    • 元の頂点を「元頂点」、追加した頂点を「追加頂点」とする。
  • 道幅 $c_i$ による最大全域木を構築していく。頂点 $u,v$ を結ぶ辺が最大全域木の辺として $k$ 個目に採用された場合、
    • $k$ 番目の追加頂点 $p_k$ を追加する。
    • その時点で $u,v$ を代表する頂点を $r_u,r_v$ とし、$p_k→r_u, p_k→r_v$ のコスト $0$ の有向辺を追加する。
    • $u,v$ を結ぶことでできた新たな連結成分を代表する頂点を、$p_k$ とする。
      • まだ1回も結ばれていない頂点を代表する頂点は、元頂点とする。

この時、以下は同じである。

  • 動物 $j$ に乗って移動可能な元頂点
  • 幅 $x_j$ 以上の辺を全て結んだ時点における、「頂点 $v_j$ が含まれる連結成分を代表する頂点」から到達できる元頂点

よって、各動物 $j$ に付き「幅 $x_j$ 以上の辺を全て結んだ時点における、頂点 $v_j$ が含まれる連結成分を代表する頂点」を $p_j$ とし、$v_j→p_j$ にコスト $0$ の有向辺を張ってやれば、 「$v_j$ に辿り着いたら動物 $j$ に乗って一定の範囲をコスト $0$ で移動できる」ことを表現できる。

頂点数は $2N-1$、辺数は $2(N-1)+M+K$ で抑えられ、Dijkstra などで $1→N$ の最短経路が答えとなる。

Python3

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