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

C++で最初のN個の自然数を差Dとなる2つの集合に分割できるか判定する方法

問題概要

この問題では、2つの整数 ND が与えられます。求めるのは、1からNまでの最初のN個の自然数を、合計値の差がちょうど D となる2つの集合に分割できるかどうかを判定することです。

具体例で理解する

入力: N = 5, D = 3

出力: Yes(可能)

説明:

1, 2, 3, 4, 5 の中から、
set1 = {1, 2, 3}、set2 = {4, 5} と分けると、その差は 3 になります。
{4+5} − {1+2+3} = 9 − 6 = 3

解法のポイント:数学的なアプローチ

この問題は、実際に集合を組み立てる前に、数学的な計算だけで判定できます。

まず、N個の自然数全体の総和は次の公式で表されます。

sum(s1) + sum(s2) = (n × (n+1)) / 2

一方、問題の条件より次の式が成り立ちます。

sum(s1) − sum(s2) = D

この2つの式を辺々加えると、

2 × sum(s1) = ((n × (n+1)) / 2) + D

ここで重要なのは、sum(s1) は整数でなければならないため、右辺が偶数である必要があるという点です。つまり、「N個の自然数の総和 + D」が偶数の場合に限り、条件を満たす分割が存在します。

C++での実装例

上記の考え方を実装したプログラムが以下の通りです。

#include <iostream>
using namespace std;
bool isSetPossible(int N, int D) {
   int set = (N * (N + 1)) / 2 + D;
   return (set % 2 == 0);
}
int main() {
   int N = 10;
   int D = 7;
   cout<<"Creating two set from first "<<N<<" natural number with difference "<<D<<" is ";
   isSetPossible(N, D)?cout<<"possible":cout<<"not possible";
   return 0;
}

実行結果

Creating two set from first 10 natural number with difference 7 is possible

まとめ

この問題の鍵となるのは、等差数列の総和公式と連立方程式の考え方です。「(N × (N+1) / 2 + D) が偶数であるか」という条件一つで判定できるため、集合を実際に構築する必要がなく、O(1) の計算量で非常に高速に答えを求められます。競技プログラミングでも頻出するテクニックなので、ぜひ覚えておきましょう。

  1. 最初のn個の自然数の二乗和を求めるC++プログラムの解説

    はじめにこの記事では、最初のn個の自然数(1からnまで)の二乗和を求める方法について解説します。例えば、n = 4 の場合、計算結果は 1² + 2² + 3² + 4² = 1 + 4 + 9 + 16 = 30 となります。基本的なアプローチとしては、1からnまで繰り返すforループを使用し、各ステップで項の二乗を計算して合計に加算していく方法があります。このプログラムの計算量は O(n) です。しかし、O(1) の定数時間で解きたい場合は、次の級数の公式を利用できます。Σk² = n(n + 1)(2n + 1) / 6この公式を使えば、ループ処理を行わずに一発で答えを求めることが可能で

  2. Pythonで最初のn個の自然数の順列からマジックセットの数を求めるプログラム

    問題の概要 最初のn個の自然数からなる配列Aと、その一つの順列P{p1, p2, ..., pn}が与えられます。このとき、以下の条件を満たす「マジックセット」と呼ばれる順列が全部でいくつ存在するかを求めます。 谷(局所最小値)の条件:位置a[1], a[2], ..., a[k]にある要素は、両隣の要素よりも小さくなければなりません。すなわち、P[a[i] - 1] > P[a[i]] < P[a[i] + 1] を満たします。 山(局所最大値)の条件:位置b[1], b[2], ..., b[l]にある要素は、両隣の要素よりも大きくなければなりません。すなわち、P[b[i]