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

C++で数列の総和を求めるプログラム:連続する整数の積の和を効率的に計算する方法


この問題では、数列を定義する2つの整数 nk が与えられます。私たちのタスクは、C++ を使って次の形式で表される数列の総和を求めるプログラムを作成することです。

(1×2×3×…×k) + (2×3×…×k×(k+1)) + (3×4×…×(k+1)×(k+2)) + … + ((n−k+1)×(n−k+2)×…×n)

各項は「連続する k 個の整数の積」で構成されており、隣接する項どうしは開始位置が1つずつずれていきます。ここでは、与えられた k の値に基づいて、この数列の総和を計算します。

入力例と出力例

入力

n = 4, k = 3

出力

30

説明

数列:(1×2×3) + (2×3×4) = 6 + 24 = 30

n = 4、k = 3 の場合、数列は「1×2×3」と「2×3×4」の2つの項から構成され、その合計は 30 になります。

解法①:二重ループによる素朴なアプローチ

最も直感的な方法は、反復処理によって総和を求めるものです。外側のループで各項の開始位置を1つずつ進めながら、内側のループで「連続する k 個の整数の積」を計算し、その値を順に加算していきます。

サンプルコード

#include <iostream>
using namespace std;

int findSeriesSum(int n, int k){
    int sumVal = 0, term = 1;
    for(int i = 1; i <= (n - k + 1); i++){
        term = 1;
        for(int j = i; j < (k + i); j++){
            term *= j;
        }
        sumVal += term;
    }
    return sumVal;
}

int main(){
    int n = 4, k = 3;
    cout << "The sum of series is " << findSeriesSum(n, k);
    return 0;
}

出力

The sum of series is 30

このプログラムは正しい結果を返しますが、二重ループを必要とするため時間計算量は O(n²) のオーダーとなり、n が大きくなるほど処理が遅くなるという欠点があります。

解法②:一般公式を使った効率的なアプローチ

この数列には便利な数学的性質があり、総和は次の一般公式から一気に求められます。

総和 = (n+1) × n × (n−1) × (n−2) × … × (n−k+1) ÷ (k+1)

この公式を使えば、ループは1つだけでよく、時間計算量は O(k) まで削減できます。実際に検証すると、n = 4、k = 3 の場合は (5 × 4 × 3 × 2) ÷ 4 = 120 ÷ 4 = 30 となり、確かに一致します。

サンプルコード

#include <iostream>
using namespace std;

int findSeriesSum(int n, int k){
    int sumVal = 1;
    for(int i = n + 1; i > n - k; i--)
        sumVal *= i;
    sumVal /= (k + 1);
    return sumVal;
}

int main(){
    int n = 4, k = 3;
    cout << "The sum of series is " << findSeriesSum(n, k);
    return 0;
}

出力

The sum of series is 30

まとめ

連続する整数の積からなる数列の総和は、二重ループでも O(n²) で求められますが、一般公式を活用すれば O(k) で効率的に計算できます。なお、n や k が大きい場合は積が急激に増大し、int 型ではオーバーフローが発生する恐れがあるため、実運用では long long 型などより大きなデータ型の使用を検討してください。数列の数学的な性質を見抜いてアルゴリズムを改良できるかどうかは、競技プログラミングや実務の両面で重要なスキルといえます。

  1. 【C++】2つの特定のノード間にパスが存在するかどうかを確認するプログラム

    グラフにおいて「ある頂点から別の頂点へ到達できるか」を判定する問題は、経路探索やネットワーク解析など、さまざまな場面で登場する基本的な課題です。本記事では、C++を用いて、指定した2つのノード(頂点)間にパス(経路)が存在するかどうかを確認するプログラムを紹介します。 アルゴリズム このプログラムでは、幅優先探索(BFS)をベースとした関数 isReach() を使い、始点 s から終点 d への到達可能性を調べます。処理の手順は以下の通りです。 開始   isReach() は、d が s から到達可能かどうかを判定する再帰的な関数である:   A) すべての頂点を「未訪問」としてマーク

  2. C++で最長増加部分列(LIS)を求めるプログラムの解説と実装例

    最長増加部分列(Longest Increasing Subsequence:LIS)とは、数列の中から一部の要素を取り出して作った部分列のうち、各要素が直前の要素よりも常に大きくなるような列のことです。本記事では、整数の集合が与えられたときに、その最長増加部分列の長さを動的計画法(DP)を用いて求める方法を解説します。問題の例入力:整数の集合 {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15} 出力:最長増加部分列の長さ → 6 該当する部分列は 0, 2, 6, 9, 13, 15アルゴリズムの考え方この問題は動的計画法を使って効率