Pythonでリストの全順列における特別な値Sの平均を計算するプログラム
問題の概要
要素のリストが与えられたとき、次のアルゴリズムに従って値Sを計算できるものとします。
while L のサイズが 1 より大きい間、繰り返す:
a := L[0]
b := L[1]
L[1] を削除
L[0] := a + b + a*b
return L[0] mod (10^9 + 7)
この問題では、リストLのすべての可能な順列(並べ替え)から計算されるSの値の平均を求める必要があります。
例えば、入力が L = [5, 3, 4] の場合、出力は 119 になります。これは、どのような順列であってもSの値が常に119になるため、その平均も119となるからです。
解法のポイント:(a+1)(b+1) − 1 の性質
この問題を効率的に解く鍵は、演算 a + b + a*b を変形することです。実は、次の恒等式が成り立ちます。
a + b + a*b = (a+1)(b+1) − 1
この性質を繰り返し適用すると、最終的なSの値は「各要素に1を加えたものの総積から1を引いた値」、すなわち
S = (x₁+1)(x₂+1)...(xₙ+1) − 1 (mod 10^9+7)
となることが分かります。積の計算結果は要素の順序に依存しないため、リストの順列がどれであってもSの値は常に同一になります。したがって、「すべての順列に対するSの平均」を求めるには、任意の一つの順列に対するSの値を計算すれば十分です。
解く手順
- m := 10^9 + 7 とする
- li := L の各要素 x に対して x+1 としたリストを作成する
- prod := 1 で初期化する
- li の各要素 i について、以下を繰り返す
- prod := prod * i
- prod := prod mod m
- (prod − 1) mod m を返す
実装例
理解を深めるために、以下のPythonコードを見てみましょう。
def solve(L):
m = 10**9+7
li = [x+1 for x in L]
prod = 1
for i in li:
prod *= i
prod %= m
return (prod-1) % m
L = [5,3,4]
print(solve(L))
入力
[5,3,4]
出力
119
計算量の考察
この解法の時間計算量は O(n)(nはリストの長さ)です。もしすべての順列(n!通り)を実際に生成してそれぞれSを計算すると、リストが少し大きくなるだけで現実的な時間では処理できません。しかし、上記の数学的性質を利用すれば、順列を列挙せずに線形時間で答えを求められます。また、各ステップで剰余(mod)を取ることで、巨大な数によるオーバーフローを防いでいる点も重要です。
-
指定された文字列のすべての順列を出力するPythonプログラム
本記事では、以下の問題に対する解決策について詳しく学んでいきます。 問題文 1つの文字列が与えられたとき、その文字列から作成できるすべての順列(並べ替えの組み合わせ)を表示する必要があります。 それでは、以下の実装例で具体的な解決策を見ていきましょう。 実装例 # リストを文字列に変換 def toString(List): return .join(List) # 順列の生成 def permute(a, l, r): if l == r: print(toString(a)) else: for i in range(l, r +
-
Pythonでリストのすべての順列を生成する方法【itertools.permutations活用】
Pythonでリストのすべての順列(並び替えのパターン)を生成したい場合は、標準ライブラリitertoolsモジュールが提供するpermutations()メソッドを使うのが最も簡単です。追加のインストールは不要で、importするだけですぐに利用できます。 基本的な使い方 itertools.permutations()にリストを渡すと、その要素をすべて並び替えた組み合わせをイテレータとして返します。結果をリストとして扱いたい場合は、list()で変換します。 import itertools perms = list(itertools.permutations([1, 2, 3]))