かっつのメモ帳

主に競プロ 時々日記

2021.08.02 problem solving

今日のCFは良いとこ無し…。

Codeforces #736 Div1B. Integers Have Friends

submission

問題自体としては No.1036 Make One With GCD 2 - yukicoder が近い。

区間GCD がセグ木で計算できることは知っていたが SWAG(未履修) を用いて求めることができるのは初耳だった。

lorent さんの実装をガン見…(ありがとうございました)

Binary GCD

除算処理を介さずに GCD が計算できると…嬉しい!

方針としては次の通り。$x, y$ を自然数として $\gcd(x,y)$ を計算することを考える。

  • $x, y$ が共に奇数になるまで $2$ で割りつつ、$\gcd(x,y)$ が素因数として $2$ を何個持つか求める。

  • $x \leq y$ として、$y := y-x$ と代入する。$x, y$ は共に奇数であったから、今 $y$ は偶数になっているので、$2$ で繰り返し割って奇数にする(ただし $y \gt 0$)。

  • $y = 0$ になるまで上の操作を繰り返す。

  • 残った $ x $ に最初求めた2ベキを掛けることで GCD が求まる。

__builtin_ctz 等を使うと簡潔に書ける。0 の場合は未定義なので予め場合分けで除いておく。

Sliding Window Aggregation

熨斗さんによる日本語記事が分かりやすかったです。ありがとうございます。

scrapbox.io

stack で次の操作をならし計算量*1 $O(1)$ で処理することを考える。

  • pop()
    • stack の末尾の要素を1つ削除する
  • push($ x $)
    • stack の末尾に $ x $ を1つ追加する
  • fold()
    • stack 内の要素の総積を計算する

これは要素の他に累積積も保持しておくことで達成できる。


この応用として、queue の操作を stack 2つでシミュレーションすることを組み合わせたのが SWAG と認識しています。

総積を計算する時は、2つの stack の末尾の積を計算すれば queue 全体の積が計算できる。

1つの要素が push, pop される回数を考えると、償却 $O(1)$ が言える。

まだ詳しく分かってないこと

  • deque も同様に stack 2つで表すことができるらしい
  • SWAG で扱うことのできる半群に対する理解

Codeforces #736 Div1C. The Three Little Pigs

submission

まず、$ i $ 日目に $ m $ 匹を選ぶ方法は $(1 + x) ^ {3 i}$ の $x^{m}$ の係数に一致する。

$1 \leq i \leq n$ についての総和が知りたいので、$f = (1 + x) ^ {3}$ とおいて、

$$ f + f^{2} + \ldots + f^{n} = \frac{f^{ n + 1 } - f }{f - 1} $$

の $x^{m}$ の係数が分かれば良い。

右辺の分子は $ x $ の $3(n+1)$ 次式であり、分母は $3$ 次式であるから多項式の割り算が線形時間で出来る。

前計算としてこの多項式を求めれば、後はクエリに対して $O(1)$ で答えられる。

*1:多分 計算量周りの記述は怪しめです