あるエンジニアのAtCoder奮闘記

東京都港区にあるアミフィアブル株式会社のエンジニアが、AtCoderで解いた問題について振り返ったりしていく会社公認のブログです。

AtCoder ABC 133 D - Rain Flows into Dams

irisruneです。弊社でRustが布教されているので試していますが、気を付けなければいけないことが多い言語なのでなかなか大変ですね。

問題

atcoder.jp

単純な連立方程式を解くだけの問題ですが、規模が大きいので一工夫必要となります。

import sys
import numpy as np


def input():
    return sys.stdin.readline().rstrip()


def main():
    n = int(input())
    a = [int(e) for e in input().split()]
    x = [0 for _ in range(n)]
    x[0] = sum(a) - (sum(a[1:n:2]) * 2)
    for i in range(2, n, 2):
        x[i] = x[i-2] + ((a[i-1] - a[i-2]) * 2)
    x[1] = sum(a) - (sum(a[2:n:2]) * 2)
    for i in range(3, n, 2):
        x[i] = x[i-2] + ((a[i-1] - a[i-2]) * 2)
    print(*x)


main()

この問題はN元連立1次方程式に変換することができます。N個の式が作れるため、X_1は計算量O(N)で求めることができます。しかし、残りのX_iを同様にして求めると全体の計算量がO(N^2)となってしまいます。

そこでX_i,X_{i+2}の関係について考えると、X_{i+2}=X_i+2A_{i+1}-2A_iとなるため、尺取り法を用いることでX_3,X_5,\ldotsを求めることができます。同様にX_2からX_4,X_6,\ldotsを求めることができるため、全体の計算量をO(N)に抑えることができます。

iの偶奇にかかわらず漸化式の形は同じなので、上記提出コードのようにループを2つに分ける意味は処理をわかりやすくする以外に特にありません。

雑記

  • 公式解説を見ればわかる通り、X_i,X_{i+1}についての漸化式が存在します。というより連立方程式のそれぞれの式が漸化式です。なので尺取り法とか考える必要は全くなかったです。

  • 連立方程式を解けさえすればいいので、ソルバーに突っ込んだりすれば非常に簡単に解けるとは思います。

    • ただし、行列の形にするとN\times N行列ができてしまうので、疎行列形式でデータを持つ必要があると思います。
    • 実はソルバーについて全く詳しくないのですが、疎行列を渡して計算時間がO(N^2)かからないソルバーってざらにあるものなのでしょうか?