1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PowerShell で Project Euler 10

Posted at

問題

10以下の素数の和は 2 + 3 + 5 + 7 = 17 である.
200万以下の全ての素数の和を求めよ.

エラトステネスの篩を使って

2000000 |
    ? {$_ -gt 0} |
    % {
        $sum = 0

        $skip = New-Object System.Collections.BitArray ($_ - 1)
        foreach($p in 2..$_)
        {
            if ($skip.Get($p - 2))
                {continue}

            for($i = $p * $p; $i -le $_; $i += $p)
                {$skip.Set($i - 2, $true)}

            $sum += $p
        }

        $sum
      }

倍数和の再帰関数を使って

ワケガワカラナイヨ

2000000 |
    ? {$_ -gt 0} |
    % {
        # √N までの素数を求める
        $sqrtN = [Math]::Floor([Math]::Sqrt($_))
        $skip = New-Object System.Collections.BitArray ($sqrtN - 1)
        $sqrtP = New-Object System.Collections.Generic.List[Int]

        foreach($p in 2..$sqrtN)
        {
            if ($skip.Get($p - 2))
                {continue}

            for($i = $p * $p; $i -le $sqrtN; $i += $p)
                {$skip.Set($i - 2, $true)}

            $sqrtP.Add($p)
        }

        # メモ化した再帰関数 M を定義
        #   M(x, y, n) = 0~n番の素数の倍数のうち、
        #   区間 [x, y] に含まれる数の総和
        $memo = @{}
        filter M ($x, $y, $n)
        {
            $sum = 0

            if ($x -gt $y)
                {return $sum}

            for (; $n -ge 0 -and $y -lt $sqrtP[$n] * $sqrtP[$n]; $n--)
                {if ($x -le $pn -and $pn -le $y)
                    {$sum += $pn}}

            if ($n -lt 0)
                {return $sum}

            $key = $x, $y, $n -join ","

            if (-not $memo.Contains($key))
            {
                foreach ($k in $n..0)
                {
                    $pk = $sqrtP[$k]
                    $i = [Math]::Max([Math]::Ceiling($x / $pk), $pk)
                    $j = [Math]::Floor($y / $pk)

                    $sum += $pk * ($j - $i + 1) * ($j + $i) / 2
                    $sum -= $pk * (M $i $j ($k - 1))

                    if ($x -le $pk)
                        {$sum += $pk}
                }

                $memo[$key] = @(0, $sum)
            }

            $memo[$key][0]++
            return $memo[$key][1]
        }

        #   「2~Nの総和」
        # - 「2~Nの√N以下の素数の倍数の総和」
        # + 「√N以下の素数の総和」
          ($_ * ($_ + 1) / 2 - 1) `
        - (M 0 $_ ($sqrtP.Count - 1)) `
        + ($sqrtP | % {$s = 0} {$s += $_} {$s})
      }

再帰関数 M の導出

準備として、関数$M'$を定義する。$M'$は自然数の集合$A \subset \mathbb{N} $の任意の要素$a \in A$の倍数であって$x$以上$y$以下の値の総和である。ただし、$x, y \in \mathbb{R}_{\ge 0}$ は非負実数とする。

$$M'(x, y, A) := \sum \left([x, y] \cap \bigcup_{a \in A} a \mathbb{N} \right)$$

ややこしいが、M' は倍数の和を表す関数である。
M' については次の性質がある。

  • $x > y \Rightarrow M'(x, y, A) = 0$
  • $M'(x, y, \emptyset) = 0$
  • $y < \min A \Rightarrow M'(x, y, A) = 0$
  • $M'(x, y, A) $$ = M'(\lceil x \rceil, y, A)$$ = M'(x, \lfloor y \rfloor, A)$
  • $x \le y \Rightarrow M'(x, y, \{ n \}) = \sum_{k = \lceil \frac{x}{n} \rceil}^{\lfloor \frac{y}{n} \rfloor} n k = \frac{n}{2} (\lfloor \frac{y}{n} \rfloor - \lceil \frac{x}{n} \rceil + 1)(\lfloor \frac{y}{n} \rfloor + \lceil \frac{x}{n} \rceil)$

実際にM'を計算する場合は次の式が使える。

$M'(x, y, \{n\} \cup A) $
$ = M'(x, y, \{n\}) $$+ M'(x, y, A) $$- M'(x, y, \{ \text{lcm}(a, n) | a \in A \})$
$ = M'(x, y, \{n\}) $$+ M'(x, y, A) $$- n M' \left(\frac{x}{n}, \frac{y}{n}, \big\{ \frac{a}{\gcd(a, n)} \big| a \in A \big\} \right)$

ただし、集合 $A = \{a_0, a_1, \dots, a_n \}$ の任意の異なる2つの要素$a_i, a_j \in A ~ (i \ne j)$が互いに素であるとき、次のように展開できる。(当然ながら異なる素数は互いに素である。)

$M'(x, y, A) $
$ = M'(x, y, \{a_n\}) $$+ M'(x, y, A \setminus \{a_n\}) $$- a_n M' \left(\frac{x}{n}, \frac{y}{n}, A \setminus \{a_n\} \} \right) $
$ = \sum_{k = 0}^n M'(x, y, \{a_{k}\}) $$ - \sum_{k = 1}^n a_k M'(\frac{x}{a_k}, \frac{y}{a_k}, A \setminus \{a_n, a_{n - 1}, \dots, a_{k} \}) $

ここで関数 M を M' によって次の通り定義する。

$$M(x, y, n) := M'(x, y, \{p_0, p_1, \dots, p_n\}) $$

ただし、$p_k \in \mathbb{P}$は素数である。添字 $n$ は$0$以上の整数であって、小さい方から素数を並べたときの順番(0 始まり)を表している。最初の3つを書けば、$(p_0, p_1, p_2) = (2, 3, 5)$である。

Mについては次の性質がある。

  • $p_n \notin [x, y] \land y \lt p_n^2 \Rightarrow M(x, y, n) = M(x, y, n - 1)$
  • $p_n \in [x, y] \land y \lt p_n^2 \Rightarrow M(x, y, n) = M(x, y, n - 1) + p_n$

さて、$N$以下の素数の個数を$\pi(N)$と書くことにする。
$p_{\pi(N) - 1} \le N \lt p_{\pi(N)}$であることに注意すると、$2, 3, \dots, N$のすべての値は、$p_0, p_1, \dots, p_{\pi(N) - 1}$ の倍数であるから、次が成り立つ。

$$M(2, N, \pi(N) - 1) = \sum_{k = 2}^{N} k = \frac{1}{2}N(N + 1) - 1$$

ところで、

$$2 \le p_k \le N \land N < p_k^2 ~ (k = \pi(\sqrt{N}), \pi(\sqrt{N}) + 1 \dots \pi(N) - 1)$$

であるから、

$$M(2, N, \pi(N) - 1) = M(2, N, \pi(\sqrt{N}) - 1) + \sum_{k = \pi(\sqrt{N})}^{\pi(N) - 1} p_k$$

すなわち、

M(2, N, \pi(\sqrt{N}) - 1) + \sum_{k = \pi(\sqrt{N})}^{\pi(N) - 1} p_k = \frac{1}{2}N(N + 1) - 1\\
\sum_{k = \pi(\sqrt{N})}^{\pi(N) - 1} p_k = \frac{1}{2}N(N + 1) - 1 - M(2, N, \pi(\sqrt{N}) - 1) \\
\sum_{k = 0}^{\pi(N) - 1} p_k = \frac{1}{2}N(N + 1) - 1 - M(2, N, \pi(\sqrt{N}) - 1) + \sum_{k = 0}^{\pi(\sqrt{N}) - 1} p_k

となるので、$\sqrt{N}$以下の素数を求めて、上記の計算をすれば素数和が求まる。

以上

おわり。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?