Processing math: 100%

AtCoder Beginner Contest 403(Promotion of AtCoder Career Design DAY)F,G問題メモ

F - Shortest One Formula

問題文

  • 正整数 N が与えられます。
  • 1, +, *, (, ) のみからなる数式のうち、値が N となるものの中で、文字列としての長さが最小のものを一つ求めてください。

制約

  • 1N2000
  • 入力は全て整数

解法

N の数式表現は、「直接“1”だけで作れる」もので無い限りは、何らかの値 k を使って、以下のいずれかの形になる。

  • [k の数式表現]+[Nk の数式表現]
  • [k の数式表現]*[N/k の数式表現]

よって、1,2,...,N について順に「最も短い数式表現」をDPで求めていける。

ただしかけ算を使う場合は、左項や右項に「括弧でくくられていない足し算」があったら括弧でくくらないといけない。
でも、最終的な答えは別に括弧でくくる必要は無い。
そのままかけ算できる形なのかどうか、分けて情報を持たせる必要がある。

  • DP1[i]:= 値が i となる数式で「直接かけ算できる」もののうち、長さが最小のものの長さ。
  • DP2[i]:= 値が i となる数式で長さが最小のものの長さ。直接かけ算できるとは限らない。

(例) 1+1111 のように括弧でくくられていない足し算がある形は DP1 の対象には含まれない。(1+11)11(1+1111) なら含まれる。

また、復元のために以下も記録する。

  • TB1[i]:=DP1[i] を達成する方法の一例
  • TB2[i]:=DP2[i] を達成する方法の一例
  • 持たせる情報例
    • (0,): '111..' という形なので直接作れる。
    • (1,x,y): 値が x になる式と y になる式を足し算で結合し括弧で囲んだ。
    • (2,x,y): 値が x になる式と y になる式を足し算で結合した。括弧では囲んでない。
    • (3,x,y): 値が x になる式と y になる式をかけ算で結合した。

O(N2) が間に合うので、各 i につき「2つの足し算に分解する方法」「2つのかけ算に分解する方法」を全て試せばよい。

途中経過を文字列として持つと時間が危ないかな? と思い復元情報のみ持たせるようにしたが、 値が n になる最短文字列長は O(logn) であると示せるので、直接持たせても O(N2logN) で大丈夫みたい。

Python3

G - Odd Position Sum Query

問題文

  • 空の数列 A があります。
  • Q 個のクエリが与えられるので順に処理してください。i 番目のクエリは以下で説明されます。
    • 整数 yi が与えられる。
    • z を、i=1 のときは 0、それ以外のときは i1 番目のクエリに対する答えとする。
    • xixi=((yi+z)mod109)+1 で定義する。
    • A の末尾に xi を追加する。
    • その後、A を昇順に並べた列を B=(B1,B2,,Bi) としたとき B の奇数番目の要素の総和を求めよ。
    • すなわち、i 以下の最大の奇数を m としたとき B1+B3+B5++Bm を求めよ。

制約

  • 1Q3×105
  • 0yi<109
  • 1xi109
  • 入力は全て整数

解法

入力として与えられるのは yi だが、クエリの実質的な入力は yi から計算で求める xi である。ただし計算に前のクエリの答えを必要とする。
これは「クエリを先読みして解く」ことを禁じる出題方法の1つと考えられる。要は「与えられた順で解けよ」と言っている。

わざわざ禁止しているということは「クエリが先読みできたら楽に解ける」可能性が高い。
先読みできない場合と全く別の解法となる可能性もあるが、ひとまず「クエリを先読みできたとしたら?」を考えてみる。
すると、前もって座標圧縮しておけば、1点更新、区間集計のセグメント木で解けることが分かる。

各ノードは Ai の値の範囲を示し、[l,r) を表すノードには以下を持たせると良い。

  • 現時点の l 以上 r 未満の Ai の個数
  • 現時点の l 以上 r 未満の Ai の小さい方から奇数番目の要素の和
  • 現時点の l 以上 r 未満の Ai の小さい方から偶数番目の要素の和

左の区間と右の区間をマージするとき、左の区間の個数の偶奇によって、 右の区間の奇数番目・偶数番目を反転させて合算するのか、そのまま合算するのかを切り替えればよい。

ただ、制約が1xi109 であるため、値を基準にセグメント木を作るには 109 オーダーの空間計算量が必要となる。
先読みできれば座標圧縮で対応できるが、今回はできない。

そこで、動的セグメント木を使う。「必要なところだけ作るセグメント木」とも呼ばれている。

まぁ、こういうデータ構造を知っているかどうか、という側面が大きい。

Pythonでは実装をちゃんとしないとTLEしてしまった。
(自作ノードクラスを作成する、再帰関数を使う、などの実装が重くなりがち。あと入力によっては辞書を使う場合)
普通に通っている人もいるので、ちょっとした実装の工夫次第で速くなるとは思うのだが。。。

Python3

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