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

C++で0を桁に含む最大d桁の正の整数の個数を求める方法


問題概要

桁数を表す整数 d が与えられます。このとき、「0」を少なくとも1つ桁に含み、最大 d 桁となる正の整数の個数を求めるのが目標です。つまり、1桁、2桁、3桁……d桁の正の整数の中から、0 を少なくとも1つ含むものをすべて数え上げます。

d桁の数の数え方

まず、d 桁の数のうち少なくとも1つの 0 を含むものの個数を求めてみましょう。例として d=3 の場合を考えます。少なくとも1つの 0 を含む3桁の数を作るには、次のような組み合わせが考えられます。

C++で0を桁に含む最大d桁の正の整数の個数を求める方法
d1(百の位)に入る数字は 1〜9 :9通り
d2(十の位)に入る数字は 0〜9 :10通り
d3(一の位)に入る数字は 0〜9 :10通り
作れる数の総数:9 × 10 × 10 = 9 × 10^2

一般化すると:
・d 桁の数の総数:9 × 10^(d-1)
・d 桁のうち 0 を一切含まない数:9^d 個
・したがって、少なくとも1つの 0 を含む d 桁の数の個数は
 9 × 10^(d-1) − 9^d = 9 × ( 10^(d-1) − 9^(d-1) )

具体例で確認してみましょう。

入力 − d=4

出力 − 0 を桁に含む最大 d 桁の正の整数の個数:2619

説明 − 各桁数における、0 を少なくとも1つ含む数の個数は次のとおりです。

1桁の数:0個
2桁の数:9個
3桁の数:171個
4桁の数:2439個
合計 = 9 + 171 + 2439 = 2619

入力 − d=1

出力 − 0 を桁に含む最大 d 桁の正の整数の個数:0

説明 − 1〜9 のいずれの数にも 0 という桁は含まれていないためです。

アプローチ①:素朴な方法(全桁を走査)

まずは for ループを使ったシンプルな方法から見ていきます。1桁から d 桁まで順番に走査し、先ほど導いた式で各桁数の個数を計算し、その都度合計に加算していきます。

  • 桁数を表す整数 d を入力として受け取ります。

  • 関数 total_count(int d) は、d 桁の数のうち少なくとも1つの 0 を含むものの個数を返します。

  • temp = 9*(pow(10,d-1) - pow(9,d-1)); として個数を計算します。

  • temp を返します。

  • 関数 maximum_d(int d) は、最大桁数 d を受け取り、d 桁以下で少なくとも1つの 0 を含む数の個数を返します。

  • ループで 1桁、2桁……と d 桁まで順に走査します。

  • 各 i について total_count(i) を計算し、count に加算します。

  • 最終的に全体の個数が得られます。

  • count を結果として返します。

アプローチ②:効率的な方法(等比数列の活用)

このアプローチでは、各桁の個数の合計が等比数列(G.P.)の和になることに着目し、まとめて計算します。

解は Σ(i=1〜d) 9 × (10^(i-1) − 9^(i-1))
= {9 × (10^d − 1)} / (10 − 1) − {9 × (9^d − 1)} / (9 − 1)
= (10^d − 1) − (9/8) × (9^d − 1)
  • d を最大桁数とします。

  • 関数 maximum_d(int d) は、最大桁数 d を受け取り、d 桁以下で少なくとも1つの 0 を含む数の個数を返します。

  • 上記の式をもとに、temp_1 = 9*((pow(10,d)-1)/9) を計算します。

  • 同様に、temp_2 = 9*((pow(9,d)-1)/8) を計算します。

  • count = temp_1 − temp_2 とします。

  • count を結果として返します。

コード例(素朴な方法)

#include<bits/stdc++.h>
using namespace std;
int total_count(int d){
    int temp = 9*(pow(10,d-1) - pow(9,d-1));
    return temp;
}
int maximum_d(int d){
    int count = 0;
    for (int i=1; i<=d; i++){
        count = count + total_count(i);
    }
    return count;
}
int main(){
    int d = 5;
    cout<<"Count of positive integers with 0 as a digit and maximum 'd' digits are: "<<maximum_d(d) << endl;
    return 0;
}

出力

上記のコードを実行すると、次の出力が得られます。

Count of positive integers with 0 as a digit and maximum 'd' digits are: 33570

コード例(効率的な方法)

#include<bits/stdc++.h>
using namespace std;
int maximum_d(int d){
    int temp_1 = 9*((pow(10,d)-1)/9);
    int temp_2 = 9*((pow(9,d)-1)/8);
    int count = temp_1 - temp_2;
    return count;
}
int main(){
    int d = 4;
    cout<<"Count of positive integers with 0 as a digit and maximum 'd' digits are: "<<maximum_d(d) << endl;
    return 0;
}

出力

上記のコードを実行すると、次の出力が得られます。

Count of positive integers with 0 as a digit and maximum 'd' digits are: 2619

まとめ

素朴な方法では1桁から d 桁まで順に計算するため計算量は d に比例しますが、等比数列の和の公式を使う効率的な方法なら、d の値に関わらず定数回の演算で答えを求められます。大きな d を扱う場合は、後者のアプローチが有利です。ただし、実際の実装では桁数が大きくなると結果が int 型の範囲を超える可能性があるため、必要に応じて long long 型などの使用を検討してください。

  1. 【C++】Cで割り切れ、範囲[A, B]に含まれない最小の正の整数を求める方法

    問題の概要今回は興味深いプログラミング問題を取り上げます。3つの整数 A、B、C が与えられたとき、「X mod C = 0」を満たし、かつ X が範囲 [A, B] に含まれない最小の正の整数 X を求めることを考えます。例えば、A = 5、B = 10、C = 4 の場合、答えとなる X の値は 4 です。これは、4 が C で割り切れ(4 ÷ 4 = 1)、かつ範囲 [5, 10] の外側に存在するためです。解法のアプローチこの問題は、以下のシンプルな手順で解くことができます。C が範囲 [A, B] に含まれない場合: C をそのまま結果として返します。C 自身が「C で割り切れ、範囲

  2. C++で積がPとなるN個の整数の最大GCDを求める方法

    2つの整数 N と P が与えられているとします。P は N 個の未知の整数の積であり、そのときそれらの整数の最大公約数(GCD)としてあり得る最大値を求めるのが課題です。 例として、N = 3、P = 24 の場合を考えてみましょう。3つの整数の組み合わせとしては {1, 1, 24}、{1, 2, 12}、{1, 3, 8}、{1, 4, 6}、{2, 2, 6}、{2, 3, 4} などが考えられます。それぞれのGCDは 1, 1, 1, 1, 2, 1 となるため、この場合の答えは 2 です。 解法のアプローチ まず P のすべての素因数を求め、ハッシュマップに格納します。各素因数が