Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonで合計が奇数になる部分配列の個数を効率的に求める方法

配列 arr が与えられます。ここで、要素の合計が奇数となる部分配列(サブ配列)の個数を求めます。答えが非常に大きくなる可能性があるため、結果は 109+7 で割った余りとして返します。

例えば、入力が arr = [8,3,7] の場合、出力は 3 になります。すべての部分配列は [8]、[3]、[7]、[8,3]、[3,7]、[8,3,7] の6つであり、それぞれの合計値は 8、3、7、11、10、18 です。このうち奇数となっているのは 3、7、11 の3つであるためです。

解法のアプローチ:累積和の偶奇に着目する

すべての部分配列を素朴に列挙すると計算量が O(n²) 以上になり、大きな入力では非効率です。そこで「累積和(prefix sum)」の偶奇を利用した効率的な手法を使います。

ある部分配列 arr[i..j] の合計が奇数になるのは、「位置 j までの累積和」と「位置 i−1 までの累積和」の偶奇が異なる場合と完全に一致します。したがって、それまでに出現した累積和のうち偶数・奇数それぞれの個数を記録しておけば、各位置で O(1) で答えに加算できます。

アルゴリズムの手順

  • freq を [1, 0] で初期化します(空の累積和 0 が偶数として最初から1つ存在するとみなすため)。
  • ans(答え)と prefix(累積和)を 0 で初期化します。
  • 配列 arr の各要素 x に対して、次の処理を繰り返します。
    • prefixx を加算します。
    • ansfreq[1 ^ (prefix & 1)](現在と逆の偶奇を持つ累積和の個数)を加算します。
    • freq[prefix & 1] を 1 増やします。
  • 最後に ans mod (10^9+7) を返します。

Pythonでの実装例

def solve(arr):
    freq = [1, 0]
    ans = prefix = 0
    for x in arr:
        prefix += x
        ans += freq[1 ^ (prefix & 1)]
        freq[prefix & 1] += 1
    return ans % (10**9+7)

arr = [8,3,7]
print(solve(arr))

入力

[8,3,7]

出力

3

計算量

時間計算量は O(n)、空間計算量は O(1)(freq は固定サイズの2要素のみ)です。配列の長さ n が非常に大きい場合でも高速に動作するのが特徴です。

  1. Pythonプログラムで数の偶数の約数の合計を求める方法

    この記事では、以下の問題文に対する解決策について詳しく解説します。 問題文:ある数が与えられたとき、その数のすべての偶数の約数(因子)の合計を求めて表示します。 アプローチ まず、与えられた数が奇数であるかどうかを確認します。奇数には偶数の約数が存在しないため、その場合は 0 を返します。 数が偶数である場合は、実際の計算に進みます。ここでのポイントは、20(つまり1)以外のすべての項を掛け合わせることで、偶数の約数の合計が得られるという点です。 偶数の約数からすべての奇数を取り除くために、20 に相当する「1」を無視します。この処理を行うことで、残るのは偶数の約数のみとなります。なお、2 は

  2. Pythonで数の奇数の約数(奇因子)の合計を求めるプログラム

    この記事では、「整数 n が与えられたとき、その数の奇数の約数(奇因子)の合計を求める」という問題の解き方を解説します。 問題文 整数 n が入力として与えられます。求めるのは、n の奇数の約数をすべて足し合わせた値です。 例えば n = 27 の場合、約数は 1, 3, 9, 27 のすべてが奇数であるため、合計は 1 + 3 + 9 + 27 = 40 となります。 アプローチのポイント この問題で最初に行うべきは、偶数の約数をすべて除外することです。 偶数の約数を取り除くには、n が 2 で割り切れなくなるまで繰り返し 2 で割ります。この操作によって n から 2 の因数が完全に