Processing math: 46%

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

E - Hierarchical Majority Vote

問題文

  • 長さ 3n(n1)01B=B1B2B3n に対して、長さ 3n101C=C1C2C3n1 を得る操作を以下のように定めます。
    • B の要素を 3 つずつまとめて多数決を取る。すなわち、i=1,2,,3n1 について、B3i2,B3i1,B3i のうち最も多く現れる値を Ci とする。
  • 長さ 3N01A=A1A2A3N が与えられます。A に上の操作を N 回適用して得られる長さ 1 の列を A=A1 とします。
  • A の要素のいくつかを 0 から 1 または 1 から 0 へ変えることを考えたとき、A の要素を最小で何個変えれば、A1 の値が変わるか求めてください。

制約

  • N1 以上 13 以下の整数
  • A0,1 からなる長さ 3N の文字列

解法

各段階で多数決を取る3つ組を子、その結果を親とする完全3分木をイメージする。

         1             ← 最終的な A'
    /   |   \
  0     1     1
 /|\   /|\   /|\
010 011 101    ← 初期状態の A

以下の木DPをする。

  • DP[v]:=(b,c)
    • b= 自身の値(0/1)
    • c= 自身の値を変えるのに、初期状態から変える必要がある最小個数

一番下の層から上に向かって求めていく。
一番下の層の左から i 番目の葉の値は (Ai,1) である。

子を持つ頂点の値を求める。b は自明として、c は以下のようになる。

  • 3 つの子の b が全て同じ値なら、c の小さい方から2つの和
  • 3 つの子の b が1対2なら、多い方の c の小さい方

DP[]c の値が答えとなる。

Python3

F - K-th Largest Triplet

問題文

  • 長さ N の整数列 A=(A1,A2,,AN),B=(B1,B2,,BN),C=(C1,C2,,CN) および整数 K が与えられます。
  • 1i,j,kN を満たす整数 i,j,k の選び方 N3 通りそれぞれに対して AiBj+BjCk+CkAi の値を計算したとき、その中で大きい方から K 番目の値を求めてください。

制約

  • 1N2×105
  • 1Kmin
  • 1\leq A_i,B_i,C_i\leq 10^9
  • 入力は全て整数

解法

f(i,j,k)=A_iB_j+B_jC_k+C_kA_i とする。
式変形とかしたくなるような形だが、あんまり関係ない。

式が単調性を持つことと、K が大きくないことが鍵。
単調性: A_p \ge A_q なら f(p,j,k) \ge f(q,j,k) となる性質。他の変数に関しても同様。

A,B,C を降順ソートすると、f(1,1,1) が必ず最大値となり、次に大きいのは f(2,1,1),f(1,2,1),(1,1,2) のいずれかとなる。
(同じ値になることはあっても)これらを飛び越えて f(2,2,1)f(1,3,1) の方が大きくなる、ということはない。

よって、優先度付きキューで (f(i,j,k),i,j,k) を大きい順に取り出し、i,j,k のいずれかを+1したものを(追加していなければ)追加する、ということを K 回繰り返せば、K 回目に取り出される値が答えとなる。

Python3

G - Many LCS

問題文

  • 長さ N の英小文字列 S および整数 M が与えられます。各 k=0,1,\ldots,N に対して以下の問題を解いてください。
  • 長さ M の英小文字列は 26^M 通りあるが、そのうち S との最長共通部分列の長さが k であるようなものの個数を 998244353 で割った余りを求めよ。

制約

  • 1\leq N\leq 10
  • 1\leq M\leq 100
  • N,M は整数
  • S は長さ N の英小文字列

解法

DPの値を状態に持つDP。

S,T が所与の時の一般的なLCS長は、以下のDPで求められる。(i,j を添字に持ち、k を値とする方法もある)

  • \mathrm{DP_{basic}}[i,k]:=T[:i]S[:j] から長さ k の共通部分列が作れるとき、j の取り得る最小値
    • T[:i]T の先頭 i 文字を表すとする。S[:j] も同様。

つまり、\mathrm{DP}[i] は、添字 k に対する数列となる。

今回はこの数列を値に持ち、以下のようにする。

  • \mathrm{DP}[i,L]:=\mathrm{DP_{basic}}[i] = L となるような長さ i の文字列の個数

L は性質上、狭義単調増加であり、1~N が含まれるか含まれないかなので、2^N 通りの状態しかない。
DPの状態数は O(2^NM) となる。

\mathrm{DP}[i-1,L] から \mathrm{DP}[i,*] への遷移を考える。
これは i 文字目に「S に出てくるどれか1文字を置く」「それ以外の文字を置く」の、最大 N+1 通りを全て試せばよい。

置く文字を決めると、一般的なLCS長のDPに基づき、O(N)L を更新できる。
置く文字を a とした時の更新後の LL_a とし、\mathrm{DP}[i,L_a] += \mathrm{DP}[i-1,L] と遷移する。
S に出てこない文字の場合は L は更新されないので、\mathrm{DP}[i,L] += \mathrm{DP}[i-1,L] \times (出てこない文字数) となる。

\alpha=\min(N,文字の種類数) として、O(2^NN\alpha M) で全て求められる。

Python3

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