C++で積がN未満となる順序対の個数をカウントする方法
問題概要
整数 N が与えられたとき、2つの正の整数からなる順序対(ペア)のうち、その積がN未満になるものをすべて数え上げることを目標とします。
この問題は、i を 1 から N 未満まで、j を 1 から i*j < N を満たす範囲まで動かしながら、条件を満たす組み合わせの数をカウントしていくことで解けます。
具体的な例で確認してみましょう。
入力例 1
N=4
出力例 1
Ordered pairs such that product is less than N: 5
説明
Pairs will be (1,1) (1,2) (1,3) (2,1) (3,1)
積が4未満となる順序対は (1,1)、(1,2)、(1,3)、(2,1)、(3,1) の5つです。順序対であるため、(1,2) と (2,1) は異なるペアとして別々にカウントされる点に注意してください。
入力例 2
N=100
出力例 2
Ordered pairs such that product is less than N: 473
説明
Pairs will be (1,1) (1,2) (1,3)....(97,1), (98,1), (99,1). Total 473.
アルゴリズムのアプローチ
- 整数 N を入力として受け取ります。
- 関数
productN(int n)は引数 n を受け取り、積が n 未満となる順序対の個数を返します。 - ペアの個数を保持する変数
countを 0 で初期化します。 - 2重の for ループを使ってペアを生成していきます。
- 外側のループは
i = 1からi < nまで、内側のループはj = 1から(i * j) < nを満たす間だけ回します。 - 条件を満たすたびに
countを 1 ずつ増加させます。 - すべてのループが完了した時点で、
countには該当する順序対の総数が格納されています。 countを結果として返します。
C++実装例
#include <bits/stdc++.h>
using namespace std;
int productN(int n){
int count = 0;
for (int i = 1; i < n; i++){
for(int j = 1; (i*j) < n; j++)
{ count++; }
}
return count;
}
int main(){
int N = 6;
cout <<"Ordered pairs such that product is less than N:"<<productN(N);
return 0;
}
出力
上記のコードを実行すると、以下の出力が得られます。
Ordered pairs such that product is less than N:10
計算量について
外側のループは最大 N−1 回、内側のループは各 i に対して最大 ⌊(N−1)/i⌋ 回実行されるため、この実装の時間計算量は O(N log N) 程度となります。
また、求めたい個数は数学的には Σ⌊(N−1)/i⌋(i = 1 〜 N−1)として表せます。これは「xy ≤ m となる格子点の個数」を数える問題と同じであり、区間ごとにまとめて計算するブロック分割(ハイパボラ法)などのテクニックを用いれば、O(√N) まで高速化することも可能です。大きな N を扱う場合は、こうした最適化を検討するとよいでしょう。
-
【C++】aの個数がbより多い部分文字列の総数を効率的に求める方法
この問題では、文字 a と b のみで構成された文字列 str と整数 N が与えられます。str を N 回繰り返して連結することで新しい文字列を作成し、その中に含まれる「a の出現回数が b より多い」部分文字列の総数を求めて出力するのが課題です。 問題の例 まず、具体的な例で問題を確認してみましょう。 入力: aab 2 出力: 9 説明: 作成された文字列は aabaab。 条件を満たす部分文字列: a, aa, aab, aaba, aabaa, aabaab, aba, baa, abaa 解法のアプローチ この問題を解くには、毎回完全な文字列を生成するのではなく、元の文字列 st
-
C++でY以下となる数値集合の最小個数を求めるアルゴリズム
問題の概要連続した数字からなる文字列と数値 Y が与えられます。このとき、以下のルールをすべて満たす集合の最小個数を求めるのが課題です。各集合は、元の文字列から連続して取り出した数字で構成すること同じ桁(文字)を複数回使用してはならない集合内の数値は Y を超えてはならない入力例と出力例たとえば、str = 1234、Y = 20 とすると、次のように 3 つの集合に分割できるため、答えは 3 になります。{12}, {3}, {4}{12} は 20 以下であり、{3} と {4} もそれぞれ 20 以下です。すべての数字が一度ずつ使われていることも確認できます。アルゴリズムこの問題は貪欲法