Loading [MathJax]/jax/output/CommonHTML/jax.js

AtCoder Beginner Contest 400 E,F,G問題メモ

AtCoder Beginner Contest 400

ABC300の前後、何回かDDos攻撃でアクセス困難になり、Unratedになることがあった。
そこから100回。今も攻撃はあるだろうけど、安定してRatedで無事開催できててすごい。

E - Ringo's Favorite Numbers 3

問題文

  • 正整数 N に対し、N が 400 number であることは以下の 2 つの条件をともに満たすことであると定義します。
    • N の素因数はちょうど 2 種類である。
    • N の各素因数 p について、Np で割り切れる回数は偶数回である。より厳密には、N の各素因数 p について pkN の約数であるような最大の非負整数 k は偶数である。
  • Q 個のクエリが与えられるので、それぞれについて答えてください。各クエリでは、整数 A が与えられるので、A 以下の最大の 400 number の値を求めてください。ただし、本問題の制約下では A 以下の 400 number は常に存在します。

制約

  • 1Q2×105
  • 各クエリについて、36A1012
  • 入力される値はすべて整数

解法

1012 以下の “400 number” を全て求めてソートしておくことができれば、各クエリには二分探索で求められる。

f(a,b,c,d) を、「(a)2b(c)2d として表される 400 number」と定義して、 一番小さい f(1,1,2,1) から経路探索のように求めていく。

(a,b,c,d) からは、以下の4つに遷移する。

  • a+1<c の場合、(a+1,b,c,d)
  • (a,b+1,c,d)
  • (a,b,c+1,d)
  • (a,b,c,d+1)

1012 を超えたら打ち切り、また一度訪れた組を再度調べないように注意すると、 1012 以下の “400 number” の個数を K として、O(K) で全列挙できる。

Python3

F - Happy Birthday! 3

問題文

  • 半径で切って N 等分された円形のケーキがあります。
  • 各ピースには時計回りに 1,2,,N の番号が付けられています。また、1iN なる整数 i についてピース i をピース N+i とも呼ぶこととします。
  • はじめ、すべてのピースの色は色 0 です。
  • あなたは、以下の操作を好きな回数行うことができます。
    • 1a,b,cN なる整数 a,b,c を選ぶ。0i<b なる各整数 i に対してピース a+i の色を色 c に変更する。この操作にはコストが b+Xc かかる。
  • 1iN なるすべての整数 i に対してピース i の色を色 Ci にするために必要なコストの合計の最小値を求めてください。

制約

  • 1N400
  • 1CiN
  • 1Xi109
  • 入力される値はすべて整数

解法

操作は、平たく言うと「好きな扇形を好きな1色に塗りつぶす」となる。

制約メタ読みで区間DPに当たりを付ける。
円環であっても区間 [l,r) は定義できる。「l>r の場合は 1N の境界を跨いでいる区間」と解釈すればよい。

  • DP[l,r]:= 区間 [l,r) を塗るのに必要なコスト

初期状態は、各 i に対し以下となる。

  • DP[i,i]=0
  • DP[i,i+1]=XCi+1

DP[l,r] を求める時、それより幅の短い区間は全て求まっているとして、 [l,m)[m,r) に分割する箇所 m=l+1,...,r1 を全探索する。

  • ピース l を色 Cl に塗る際に m を跨がない場合は、単純に足し合わせ。
    • DP[l,m]+DP[m,r]
  • Cl=Cm の時に限り、ピース m を塗る際に、l まで一緒に塗っていたことにできる。
    • 追加分のコストは、区間を伸ばした分 ml
    • DP[l+1,m]+DP[m,r]+(ml)

一見、なんかもっと他の遷移も考えなきゃいけないように思うが(m を塗る際に l までは一緒には塗らないが、その手前のどこかまでは一緒に塗る場合、など)、 その場合は他の分割箇所 m でちゃんと考慮されるので、上記の遷移だけでいける。

これでDPを埋めていき、幅 N の区間に対するDPの結果の中での最小値が答え。
(※定義上、幅 N の区間の格納場所は DP[i,i] となり、初期状態の幅0の区間とダブってしまうので、幅 N の場合だけはどこか別の場所に記録しておくとよい。他の区間を求める時に参照されることはないし)

計算量は O(N3)

Python3

G - Patisserie ABC 3

問題文

  • ABC 洋菓子店で働くパティシエである高橋君は、AtCoder Beginner Contest 400 を記念したケーキのセットを販売することにしました。
  • ABC 洋菓子店にはケーキ 1, ケーキ 2, , ケーキ NN 種類のケーキが販売されています。
  • 各ケーキは綺麗さ、おいしさ、人気度の 3 つの非負整数値を持ちます。具体的にはケーキ i の綺麗さ、おいしさ、人気度はそれぞれ Xi,Yi,Zi です。
  • 高橋君はケーキを被りのない K 個のペアにして売り出すことを考えました。
    • 形式的に説明すると、2K 個の 相異なる 1 以上 N 以下の整数 a1,b1,a2,b2,,aK,bK を選んでケーキ ai とケーキ bi をペアにすることにしました。
    • ケーキ ai とケーキ bi をペアにした時のペアの価格は max(Xai+Xbi,Yai+Ybi,Zai+Zbi) とします。ただし、max(P,Q,R)P,Q,R のうち最大の値を表します。
  • K 個のペアの価格の総和としてあり得る最大の値を求めてください。
  • T 個のテストケースが与えられるので、それぞれについて答えを求めてください。

制約

  • 1T1000
  • 2N105
  • 各入力ファイルについて、すべてのテストケースの N の総和は 105 以下である。
  • 1KN2 (実数 x に対し、xx 以下の最大の整数を表す。)
  • 0Xi,Yi,Zi109
  • 入力はすべて整数

解法

ケーキの「強み」を、「そのケーキの3つのカテゴリの中で最大値を取るものの1つ」とする。
(Xi,Yi,Zi)=(3,4,5) なら、ケーキ i の強みはカテゴリ Z。同率の場合は適当に1つ)

以下のような問題に言い換えられる。

  • 整数の多重集合 Sx,Sy,Sz があり、最初は空である。
  • 各ケーキ i につき、以下のいずれか1つをおこなう。
    • XiSx に追加する
    • YiSy に追加する
    • ZiSz に追加する
    • 何もしない
  • 最終的に、以下の条件を満たすような分け方に対し、
    • |Sx|+|Sy|+|Sz|=2K
    • |Sx|,|Sy|,|Sz| は全て偶数
  • スコアを sum(Sx)+sum(Sy)+sum(Sz) とする。スコアの最大値を求めよ

集合の中でのペア分けは適当にやればよい。 (Sx に追加したケーキ i,j をペアにしたとき、実際には Xi+Xj より Yi+Yj が最大となるようであれば、 i,jSy に入れていた方が全体の総和は大きくなるため、そもそもが最大値となる分け方ではなかったことになる)

集合に追加する 2K 個の要素はなるべく値の大きいもの(そのケーキの強みであるもの)を選びたい。

ケーキを max(Xi,Yi,Zi) の大きい順に並べ、indexを振りなおす。

ケーキ 12K につき、そのケーキの強みを採用する(Xi が最大値なら Sx に追加する)のが素朴な上限である。
この結果、「|Sx|,|Sy|,|Sz| は全て偶数」が満たされていれば、明らかにそれが答え。

だが、実際は奇数個の集合ができることもありうる。
その場合、強み以外を使ったり、2K+1 以降のケーキを使ったりして、組み替える必要がある。

これを、どう上手く処理するか?

ところで、「どのカテゴリを使うか」はともかく「どのケーキを使うか」という観点では、 「最適解には、12K のケーキのうち使わないのが2個以下であるものが存在する」ということが証明できる。

  • もし、使わなかったうち2つの強みが共通している場合
    • その2つを使っていたことにして損しない。
    • よって、使わなかったケーキ同士で、強みは全て異なっている。
    • 4個以上だと絶対被るので、使わないのは最大でも3個。
  • 使わなかったのが3個で、強みが全て異なる場合
    • 2K+1 個目のケーキの強みが例えば X なら、使わなかった3個のうち、X が強みであるものとペアにして損しない。

また、Sx,Sy,Sz は要素数の偶奇だけが重要のため、具体的な個数はどうでもよい。

以上から、以下のDPでケーキ 12K の使用状態を網羅できる。

  • DP[i][j][k][l][m]:=
    • ケーキ i まで見て、
    • 採用していないのが j={0,1,2} 個で、
    • |Sx| の偶奇が k={0,1} で、
    • |Sy| の偶奇が l={0,1} で、
    • |Sz| の偶奇が m={0,1} である分け方のスコア

k,l,m は、実装上は3bitのフラグでまとめてしまえばよい。状態数 48K で求められる。

後は、2K+1N で、各パラメータが大きいケーキの上位2個までを求め、DP結果の不採用数に応じて穴を埋めたものが答えとなる。
(またはDPを継続して、2K+1 以降は今度は採用するたびに j を減らしていく、という実装もでき、そちらの方が楽かも)

Python3

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