C++で最初のN個の自然数の2乗の和がX以下となる最大のNを求める方法
概要
整数 X が与えられたとき、最初の N 個の自然数の2乗の和が X を超えないような最大の N を求めるのが本記事の目的です。
入力例と出力例
例1
X = 7
出力:
2
N = 3 の場合、級数の和は 12 + 22 + 32 = 1 + 4 + 9 = 14 となり X を超えてしまうため、2 が N の最大値となります。
例2
X = 27
出力:
3
N = 4 の場合、12 + 22 + 32 + 42 = 1 + 4 + 9 + 16 = 30 となり X を超えるため、3 が最大値となります。
解法アプローチ
単純な解法(線形探索)
最もシンプルな方法は、1 から順にループを実行し、S(N) ≤ X を満たす最大の N を見つけることです。ここで S(N) は最初の N 個の自然数の2乗の和を表し、次の公式で求められます。
S(N) = N × (N + 1) × (2N + 1) / 6
ただし、この手法の時間計算量は O(N) であり、X が大きくなると非効率になる点に注意が必要です。
効率的な解法(二分探索)
S(N) は N に対して単調増加するため、二分探索を用いることでより効率的に問題を解くことができます。手順は以下の通りです。
探索範囲 [low, high] の中央値 mid を (low + high) / 2 として計算する
squareSum(mid) ≤ X が成り立つ場合、mid は条件を満たす候補となるため答えを更新し、low を mid + 1 に設定してさらに大きい N を探索する
そうでない場合、mid では和が X を超えるため、high を mid − 1 に設定して小さい側の範囲を探索する
この手法の時間計算量は O(log N) であり、非常に高速に動作します。
C++実装例
// C++による実装例
#include <bits/stdc++.h>
using namespace std;
#define ll long long
// 最初の N1 個の自然数の2乗の和を返す関数
ll squareSum(ll N1){
ll sum1 = (ll)(N1 * (N1 + 1) * (2 * N1 + 1)) / 6;
return sum1;
}
// 最初の N 個の自然数の2乗の和が
// X を超えないような最大の N を返す関数
ll findMaxN(ll X){
ll low1 = 1, high1 = 100000;
int N1 = 0;
while (low1 <= high1) {
ll mid1 = (high1 + low1) / 2;
if (squareSum(mid1) <= X) {
N1 = mid1;
low1 = mid1 + 1;
}
else
high1 = mid1 - 1;
}
return N1;
}
// ドライバーコード
int main(){
ll X = 27;
cout << findMaxN(X);
return 0;
}出力
3
-
【PHP】「x」または「y」で割り切れる1〜nの自然数の合計を求めるプログラム
「x」または「y」で割り切れる、1からnまでの自然数の合計を求めたい場合、単純にループで一つずつ判定する方法もありますが、等差数列の和の公式と包除原理を組み合わせれば、ループなしで効率的に計算できます。ここではその実装例を紹介します。サンプルコード<?phpfunction sum_of_nums($n_val, $x_val, $y_val){ $val_1 = floor($n_val / $x_val) * ((2 * $x_val) + (floor($n_val / $x_val) - 1) * $x_val) / 2;
-
Pythonで「最初のN個の自然数の2乗和がX以下」となる最大のNを二分探索で求める方法
整数 X が与えられたとき、「最初の N 個の自然数の2乗の合計が X を超えない」ような最大の N を求める問題を考えてみましょう。 例えば、X = 7 の場合を考えます。N = 3 とすると、1² + 2² + 3² = 1 + 4 + 9 = 14 となり、X = 7 を超えてしまいます。一方、N = 2 なら 1² + 2² = 5 であり、X 以下に収まります。したがって、答えは 2 となります。 解法のアプローチ この問題は、次の手順で二分探索(バイナリサーチ)を使うことで効率的に解くことができます。 まず、2乗和を計算する関数 sum_of_squares() を定義します。引