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

Pythonでリストのすべての部分列の総和Sに対する2^Sの合計を効率的に求めるプログラム

リスト A が与えられたとします。ここで、A のすべての空でない部分列(サブリスト)を考えます。n 個の要素を持つリストには (2n − 1) 個の空でない部分列が存在することが知られています。それぞれの部分列について要素の総和(sublist_sum)を計算し、それらを S1, S2, S3, …, S(2N−1) と表します。

そして、次のような特別な総和 P を定義します。

P = 2S1 + 2S2 + 2S3 + … + 2S(2N−1)

この P の値を求めるのが目的です。ただし、P は非常に大きな値になる可能性があるため、P mod (109 + 7) を返します。

入力例と出力例

たとえば、入力が A = [2, 2, 3] の場合、出力は 224 になります。各部分列と対応する値は次のとおりです。

  • {2} → 22 = 4
  • {2} → 22 = 4
  • {3} → 23 = 8
  • {2, 2} → 24 = 16
  • {2, 3} → 25 = 32
  • {2, 3} → 25 = 32
  • {2, 2, 3} → 27 = 128

これらを合計すると、4 + 4 + 8 + 16 + 32 + 32 + 128 = 224 となります。

解法のアプローチ

すべての部分列を実際に生成していては、部分列の数が要素数に対して指数的に増えるため非効率です。ここで重要なのは、各要素について「その要素を部分列に含めるか、含めないか」という2択しかないという点です。積 ∏(1 + 2el) を展開すると、各項がちょうど1つの部分列に対応するため、次の関係が成り立ちます。

空でない部分列に対する P = ∏(1 + 2el) − 1

「−1」は、空集合(総和 0、寄与 20 = 1)の分を差し引くためです。したがって、以下の手順で O(N) 時間で答えを求められます。

  • ans := 1、m := 109 + 7 と初期化する
  • A の各要素 el について:
    • ans := ans × (1 + (2el mod m))
    • ans := ans mod m
  • (m + ans − 1) mod m を返す

Pythonでの実装例

以下の実装を見ると、仕組みの理解が深まるでしょう。

def solve(A):
   ans=1
   m=10**9+7

   for el in A:
      ans *= (1+pow(2,el,m))
      ans %= m
   return (m+ans-1) % m


A = [2,2,3]
print(solve(A))

入力

[2,2,3]

出力

224
  1. Pythonで数値が2の累乗かどうかを判定するプログラム

    本記事では、与えられた数値が2の累乗(べき乗)であるかどうかを判定する方法について、考え方と実装手順をわかりやすく解説します。 問題の定義 ある整数 n が与えられたとき、その数が2の累乗(1, 2, 4, 8, 16, …)であるかどうかを判定します。 アプローチ 判定には「繰り返し2で割る」というシンプルな方法を使います。考え方は以下の通りです。 入力された数値 n を、1になるまで繰り返し2で割っていきます(n = n // 2)。 割る過程で n % 2 の結果が0以外(奇数)になり、かつ n が1でない場合は、その数は2の累乗ではありません。 最終的に n がちょうど1になれば、そ

  2. Pythonで配列(リスト)の合計を求める方法をわかりやすく解説

    この記事では、配列(リスト)の合計値を求めるという問題に対して、Pythonでの解決策とアプローチをわかりやすく解説します。 問題の定義 配列が入力として与えられたとき、その配列に含まれるすべての要素の合計を計算することを目標とします。 例えば、[1, 2, 3, 4, 5] という配列が与えられた場合、出力は 15 になります。 アプローチ1:ループを使った素朴な方法(総当たり法) 最も基本的な方法は、リストを先頭から順に走査し、各要素を合計用の変数に加算していくやり方です。手順は以下の通りです。 合計を格納する変数を 0 で初期化します。 for ループでリストの各要素を取り出し、順番に