【C++】Nで割り切れるレピュニット(繰り返し単位)の最小桁数を効率的に求める方法
はじめに
本記事では、指定された整数Nで割り切れる「レピュニット(繰り返し単位)」の桁数kを求める問題について解説します。レピュニットとは、数字の1のみが繰り返される数のことで、R(k)は1がk個並んだ数を表します。例えば、R(4) = 1111 となります。ここでの課題は、R(k)がNで割り切れるような最小のkを求めることです。
入力 : N = 13 出力 : k = 6 説明 : R(6)、つまり 111111 は 13 で割り切れます。 入力 : N = 31 出力 : k = 15
解法へのアプローチ
この問題に対する最も素朴なアプローチは、k = 1から順に各値をチェックし、R(k)がNで割り切れるかどうかを確認することです。しかし、この方法ではNがどのR(k)によっても割り切れない場合の判定が困難で、プログラムが複雑になりすぎたり、正しく動作しなかったりする可能性があります。
より効率的なアプローチは以下の通りです。
- まず、Nが10と互いに素(coprime)であるかどうかを確認します。
- 互いに素でない場合、どのkに対してもR(k)はNで割り切れません。
- 互いに素である場合、R(1)、R(2)、R(3)…と各レピュニットについて、R(i)をNで割った余りを計算します。これにより複数の余りが得られます。
- R(i)とR(j)で同じ余りの値が現れた場合、その差 R(i) − R(j) はNで割り切れることになります。
- R(i)とR(j)の差は、あるレピュニットに10のべき乗を掛けた形になります。10とNは互いに素なので、そのレピュニットR(k)はNで割り切れることが保証されます。
C++による実装例
#include <bits/stdc++.h>
using namespace std;
int main() {
int N = 31;
int k = 1;
// Nが10と互いに素かどうかを確認
if (N % 2 == 0 || N % 5 == 0){
k = 0;
} else {
int r = 1;
int power = 1;
// 余りが0になる(Nで割り切れる)までループ
while (r % N != 0) {
k++;
power = power * 10 % N;
r = (r + power) % N;
}
}
cout << "Value for k : "<< k;
return 0;
}
出力結果
Value for k : 15
まとめ
本記事では、与えられた整数Nで割り切れるレピュニットR(k)の最小桁数kを求める方法について解説しました。「Nが10と互いに素であるか」を判定し、剰余計算を活用することで効率的に答えを導けることを説明しました。また、この問題を解くためのC++のコードも紹介しました。ロジックは同じなので、Java、C、Pythonなど他の言語でも容易に実装できます。本記事が皆様の学習のお役に立てば幸いです。
-
C++とOpenCVを使って線を描画する方法
OpenCVで線を描画するには、始点と終点の2つの座標が必要です。さらに、線を描くためのキャンバス(描画領域)も用意しなければなりません。線を描画するために必要な要素OpenCVでは、キャンバスとして機能するのが行列(Mat)です。この行列に対して、線の始点と終点を定義し、加えて以下の情報も指定します。線の色線の太さつまり、OpenCVで線を描くには、行列・2つの点・色・線の太さという4つの要素を宣言しておく必要があります。必要なヘッダーファイルOpenCVで線を描画するには、<imgproc.hpp>ヘッダーをインクルードします。これは、line()関数がこのヘッダー内で定義され
-
C++でN階乗の合計の下一桁(一の位)を求める方法
この記事では、C++を使って「1! + 2! + ... + N!」という階乗の合計の下一桁(一の位)を求める方法を解説します。例えばN = 3の場合、1! + 2! + 3! = 9 となるため答えは9、N = 4の場合は 1! + 2! + 3! + 4! = 33 となり、下一桁は3になります。階乗の下一桁の重要な性質この問題を解く鍵となるのは、5以上の数の階乗の下一桁が必ず0になるという性質です。5! = 120、6! = 720、7! = 5040 のように、5!以降はすべて一の位が0になります。これは、5以上の階乗には必ず因数2と5のペアが含まれ、10の倍数になるためです。したがっ