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

Pythonで解く:分配ルールに従ってキャンディを配れる子どもの人数を求めるプログラム

ここでは、k個のキャンディを子どもたちに分配する問題を考えます。ただし、分配には以下のルールがあります。

  • i番目の子どもは、ちょうど i² 個のキャンディを受け取る
  • i番目の子どもは、1番目から i−1 番目までの子ども全員に配り終わるまで、キャンディを受け取れない
  • i番目の子どもが i² 個を受け取れない場合、その分配は無効とみなされる

例えば、入力が k = 20 の場合、出力は 3 になります。1番目の子どもが1個、2番目の子どもが 2² = 4個、3番目の子どもが 3² = 9個を受け取り、合計14個が消費されます。4番目の子どもには 4² = 16個が必要ですが、残りは6個しかないため、この分配は無効です。したがって、キャンディを配れるのは3人までということになります。

解き方のアプローチ

この問題は二分探索(バイナリサーチ)を使うことで効率的に解けます。ポイントは、n番目までの子どもに配るために必要なキャンディの総数が、平方数の和の公式 n(n+1)(2n+1)/6 で計算できることです。この値が k を超えない最大の n を二分探索で見つけます。

  • left := 0、right := k として初期化する
  • right − left > 1 の間、次の手順を繰り返す
    • mid := (left + right) / 2 の切り捨て値とする
    • mid × (mid + 1) × (2 × mid + 1) / 6 の切り捨て値が k より大きければ right := mid、そうでなければ left := mid とする
  • right × (right + 1) × (2 × right + 1) ≤ k × 6 であれば right を返す
  • それ以外の場合は left を返す

この方法により、計算量は O(log k) となり、k が非常に大きな値でも高速に答えを求められます。

実装例

理解を深めるために、以下のPythonコードを見てみましょう。

def solve(k):
left = 0
right = k
while (right - left > 1):
mid = (left + right) // 2
if (mid * (mid + 1) * (2 * mid + 1) // 6 > k):
right = mid
else:
left = mid
if (right * (right + 1) * (2 * right + 1) <= k * 6):
return right
return left

k = 20
print(solve(k))

入力

20

出力

3

このように、平方数の和の公式と二分探索を組み合わせることで、「何人目までキャンディを配れるか」という問題をシンプルかつ効率的に解くことができます。

  1. Pythonで行列の転置を求めるプログラム

    この記事では、与えられた問題に対する解法とアプローチについて詳しく解説します。 問題文 ある行列が与えられたとき、その転置を同じ行列に格納し、結果を表示する必要があります。 行列の転置とは、行を列に、列を行に入れ替えたものです。言い換えれば、行列Aの転置は、要素A[i][j]をA[j][i]と入れ替えることで得られます。 実装例 N = 4 def transpose(A): for i in range(N): for j in range(i+1, N): A[i][j], A[j][i] = A[j][i], A[i][j] # ドライ

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

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