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

E - Sum of Subarrays

問題文

  • 長さ $N$ の整数列 $A = (A_1, A_2, \ldots, A_N)$ が与えられます。
  • $Q$ 個のクエリが与えられるので、それぞれについて答えを求めてください。
    • $i$ 番目のクエリでは、整数 $L_i, R_i$ が与えられます。
    • $A$ の区間 $[L_i,R_i]$ 内にある全ての「連続部分列の和」の総和を求めてください。
    • つまり、$\displaystyle\sum_{l = L_i}^{R_i}\sum_{r = l}^{R_i}\sum_{j = l}^{r} A_j$ を求めてください。

制約

  • $1 \leq N, Q \leq 3 \times 10^5$
  • $1 \leq A_i \leq 100$
  • $1 \leq L_i \leq R_i \leq N$
  • 入力される値はすべて整数

解法

$i^2A_i, iA_i, A_i$ のそれぞれの累積和を持つことで解ける。

解法2

毎度おなじみのセグメント木解法。(思考停止ともいう)

「セグ木にのせるもの」と「マージする方法」を考えればよい。
結論から言うと、区間 $x$ に以下の5つの情報を持たせるとできる。

  • $x_1$: 区間長
  • $x_2$: 区間の $A_i$ の総和
  • $x_3$: 区間の全ての部分列の総和の総和(求めたいもの)
  • $x_4$: 部分列のうち、左端要素を使うものの総和の総和
  • $x_5$: 部分列のうち、右端要素を使うものの総和の総和
 x
[ 1  2  3  4 ]

x4の対象となる部分列
  1
  1  2          x4 = (1)+(1+2)+(1+2+3)+(1+2+3+4) = 20
  1  2  3
  1  2  3  4

x5の対象となる部分列
           4
        3  4    x5 = (4)+(3+4)+(2+3+4)+(1+2+3+4) = 30
     2  3  4
  1  2  3  4

(※$x_5$ は $x_1,x_2,x_4$ から求められるので不要といえば不要。まぁあった方が考えやすい)

$a=(1,2,3),b=(4,5,6,7)$ とし、マージした区間を $c$ とすると、$c_1,c_2$ は自明な足し算で求められる。
$c_4$ は以下のようにして求められる。左右逆転して同様に $c_5$ も求められる。

[ 1  2  3  4  5  6  7 ]

c4の対象    a4
  1       ↙
  1  2
 _1__2__3_         b4
  1  2  3| 4     ↙
  1  2  3| 4  5
  1  2  3| 4  5  6
  1  2  3| 4  5  6  7
     ↑
   a2*b1

$c_3$ は、以下のようにして求められ、$a_3+b_3+a_5b_1+b_4a_1$ となる。

マージ境界をまたがないもの: a3, b3

またぐもの: 左右別にそれぞれがどれだけ寄与するかで考える

    a5             b4
        3      4
     2  3  ×  4  5
  1  2  3      4  5  6
               4  5  6  7

  a5 側の各部分列は、右をどこまで伸ばすかが b1 通りずつある → a5 * b1
  b4 側の各部分列は、左をどこまで伸ばすかが a1 通りずつある → b4 * a1

これでマージができるので、セグメント木に載せると $O(N + Q \log{N})$ でできる。

Python3

F - Loud Cicada

問題文

  • AtCoder 島には $N$ 種類のセミが生息しています。種類 $i$ のセミ ($1 \leq i \leq N$) は $A_i$ の倍数の年にのみ大量発生します。
  • $1$ 年から $Y$ 年までの $Y$ 年間のうち、ちょうど $M$ 種類のセミが大量発生する年が何回あるかを求めてください。

制約

  • $1 \leq M \leq N \leq 20$
  • $1 \leq Y \leq 10^{18}$
  • $1 \leq A_i \leq 10^{18}$ ($1 \leq i \leq N$)
  • 入力される値はすべて整数

解法

素数ゼミをテーマとした問題。
包除原理っぽいが、いつもとはちょっと違い「ちょうど $M$ 種類」のものを求めたい。

いつもの包除原理なら $\displaystyle \sum_{S}(-1)^{|S|} f(S)$ などのような式($f$ は適当な関数)になるが、 これは「少なくとも1つの条件に当てはまる」や「どの条件にも当てはまらない」$f(S)$ の合計を求めることになり、 ここからでは「ちょうど $M$ 個の条件に当てはまる」場合は求まらない。

N=3 M=2
  ┌──┐      □□□
┌┼─┐│    □■■□    黒いとこだけのf(S)を求めたい
││┌┼┼┐  □■□■□
│└┼┼┘│  □□■□□
└─┼┘  │      □□□
    └──

あるセミの種類の集合 $S=\{i_1,i_2,...\}$ に対し、 そいつらが揃って大量発生する周期は $\mathrm{LCM}(A_{i1},A_{i2},...)$ であり、 $Y$ 年間の中での発生回数は $C_S = \left \lfloor \dfrac{Y}{\mathrm{LCM}(A_{i1},A_{i2},...)} \right \rfloor$ である。

(※この時、LCMはまともに計算すると巨大になり得るので注意。 途中で $Y$ を超えたら $C_S=0$ に決まるので、計算を打ち切ってよい)

$C_S$ を、$|S| \ge M$ である全ての $S$ について計算しておく。
さらに、$|S|$ ごとに計算結果をまとめておく。$\displaystyle D_d = \sum_{|S|=d}C_S$

すると、答えは以下で求められる。($N=4,5$ くらいで必死に書き出すとエスパーできる)

  • $\displaystyle \sum_{d=M}^{N}(-1)^{d-M} \binom{d}{M} D_d$

証明は「真の答え」と「$C_S$ を合計しただけのダブりを含んだ答え $D_d$」の間に計算式をたて、式変形することで導出できる。

Python3

解法2

$H_S$ を、「$S$ に含まれる種類のセミのみが大量発生する年の数」とする。

前の解法の $C_S$ は「$S$ に含まれる種類のセミが大量発生する年の数」であり、他のセミも大量発生しているケースが含まれている。

$S$ をbitフラグで表し、たとえば $N=5, S=10110$ とすると、以下が成り立つ。

  • $C_{10110} = H_{10110}+H_{10111}+H_{11110}+H_{11111}$

つまりは、$C_S$ は「$S$ を含む集合 $T$ 全てに対する $H_T$ の総和」なので、まさしく $H$ と $C$ はゼータ変換の前と後という関係になる。

$C$ から $H$ を求めたいなら、メビウス変換すればよい。
その後、$|S|=M$ の箇所のみ $H_S$ を足し合わせれば、答えとなる。

G - Small Multiple 2

問題文

  • 以下の $2$ つの条件を満たす正の整数 $n$ としてあり得る最小値を求めてください。
    • $n$ は $K$ の倍数である。
    • $n$ の十進法での表記には、部分文字列として $S$ が含まれる。
  • $T$ 個のテストケースが与えられるので、それぞれについて答えを求めてください。

制約

  • $T$ は整数。
  • $1 \leq T \leq 200$
  • $K$ は整数。
  • $1 \leq K \leq 10^9$
  • $S$ は数字 ('0' - '9') からなる文字列。
  • $S$ の先頭の文字は '0' でない。
  • $1 \leq |S| \leq 5 \times 10^5$
  • すべてのテストケースの $|S|$ の総和は $5 \times 10^5$ 以下である。

解法

制約から、実は $S$ に追加されうる文字列の長さは非常に短い、と気付くところが最初のポイント。

$K \le 10^9$ より、とりあえず $S$ の後ろに9桁を追加して、 000000000~999999999 まで $1$ ずつ増やしていくと、どこかで $\mod{K}$ が $0$ になる接尾辞が存在する。
$n$ の桁数、つまりは「$S$ の前後に追加する文字列長の合計」は小さい方が絶対に数値として小さいので、 $S$ に追加される桁数は多くても9桁である。

前と後ろに付ける文字列をそれぞれ以下のように表す。

  • 前に付ける数値(を表す文字列)を $X$、桁数を $d$ とする(leading-zeroなし)
  • 後に付ける数値(を表す文字列)を $Y$、桁数を $e$ とする(leading-zeroあり)

ただし便宜上、$X=0$ のとき、$d=0$ として解釈する。同様に、$Y=0$ の時のみ $e=0$ であってもよいものとする。

この時、以下の式を満たすことが、$n$ が $K$ の倍数となる条件となる。(※ここでは、$X,S,Y$ は数値として解釈している)

  • $(X \times 10^{|S|} + S) \times 10^e + Y \equiv 0 \mod{K}$ … ①

$d+e \le 9$ より、前か後ろの短い方に付ける文字列の長さは $4$ 以下である。 短い方を $0~9999$ まで全探索し、その時にもう一方の最適値がすぐに求められるのであれば、探索候補は $2 \times 10^4$ 個くらいに絞られる。 計算量も、$10^4$ に「$X$ から $Y$ を求める計算量」(またその逆)をかけたくらいのオーダーで求められ、間に合いそうである。

ただし、$Y$ は $e$ の値によっても結果が違ってきたりなどするので、ちゃんと考えると

  • $X$ を $0~10^4$ で仮定
    • → $\mod{K}$ が $0$ になる最小の $e$、その中で最小の $Y$ を求める
  • $e$ を $0~4$、$Y$ を $0~10^e$ で仮定
    • → $\mod{K}$ が $0$ になる最小の $X$ を求める

以上を全探索してその中での最小値を求めればよいことになる。これでもオーダーとしては $O(\sqrt{K}) \simeq 10^4$ のままである。

この解法において必要となるのは以下である。

  • $F(X)$ : $X$ を仮定したら $(e,Y)$ を求める関数
  • $G(e,Y)$ : $(e,Y)$ を仮定したら $X$ を求める関数
  • $(X,Y,d,e)$ の大小比較方法(実際に $n$ を作ったときにどちらが小さいか)
$F(X)$

$F(X)$ については、式①に $X$ を代入し、 また $e$ を仮定して代入すると、$Y$(として取り得る非負の最小値)が求まる。 $e=0~9$ を小さい方から順に試し、最初に $e \ge |Y|$ となったらそれが最小の $(e,Y)$ となる。
1回当たりの計算量は $O(\log{K})$。

$G(e,Y)$

$G(e,Y)$ については、式①に代入すると $X \times p \equiv q$ という形になる($p,q$ は既知の値)。
この式は、$q$ が $\gcd(p,K)$ の倍数である場合のみ解を持つ。 $g=\gcd(p,K)$ とすると、$X \equiv \dfrac{q}{g} \left ( \dfrac{p}{g} \right )^{-1} \mod{\dfrac{K}{g}}$ となり、求まる。
1回当たりの計算量は、GCDやmod逆数を求めるのに $O(\log{K})$。

任意modの逆数の計算は、pythonなら pow(a, -1, mod) でできる(便利!)が、 そのような関数が無い場合は、ユークリッドの互除法を拡張して求められる。

大小比較

$(X,Y,d,e)$ の大小比較についても、意外と一筋縄ではいかない。
実際に $n$ を生成したらオーバーフローするし、文字列のまま比較しようとしても $10000$ 回も $|S| \simeq 5 \times 10^5$ の長さの文字列生成が発生したらTLEとなる。

まずは以下の条件によって残す候補を絞り込む。これらは $(X,Y,d,e)$ のみからほぼ $O(1)$ で判定可能。

  • まず $d+e$ が小さい方
  • $d+e$ かつ $d$ が同じ中では、$X$ が小さい方
  • これらが全て同じ中では $Y$ が小さい方

すると候補は $(d,e)=(0,d+e)~(d+e,0)$ の $d+e+1 \le 10$ 通りにまで抑えられる。
あとは実際に文字列生成して比較しても間に合う。

Python3

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