MOD 逆数
を整数とすると,
と互いに素な任意の整数
に対し,
を満たす整数
がただ一つ存在します.この
を,
を法としたときの逆数といい,競技プログラミングで頻繁に役立ちます.今回はこれを計算するコードを C で書いていきます.
数学的な解き方
ならば,ある整数
が存在して
です.すると,これは
と書き換えられます.ここで
を
で割った余りを
とすると,
となります.これを繰り返すことで
を求めることができます.具体的には,
とすると
一般化
上の例より,,
とし,
行列
上の手続きを行列を用いて表すと
コード
この行列計算をそのままコードで書くと次のようになります.
int inverse(int mod, int val){
int x[2] = {mod, val};
int a[2][2][2] = {{{1, 0}, {0, 1}}};
int i;
for(i = 0; x[!i]; i ^= 1){
a[!i][0][0] = a[i][0][1] - x[i] / x[!i] * a[i][0][0];
a[!i][0][1] = a[i][0][0];
a[!i][1][0] = a[i][1][1] - x[i] / x[!i] * a[i][1][0];
a[!i][1][1] = a[i][1][0];
x[i] = x[i] % x[!i];
}
return a[!i][0][0];
}実際には行列の第 1 行と第 2 行の計算は独立しているので次のように書けます.
int inverse(int mod, int val){
int x[2] = {mod, val};
int a[2][2] = {{1, 0}};
int i;
for(i = 0; x[!i]; i ^= 1){
a[!i][0] = a[i][1] - x[i] / x[!i] * a[i][0];
a[!i][1] = a[i][0];
x[i] = x[i] % x[!i];
}
return a[!i][0];
}さらに第 1 列と第 2 列を配列内で毎回ひっくり返すようにすると次のようになります.
int inverse(int mod, int val){
int x[2] = {mod, val};
int a[2] = {1, 0};
int i;
for(i = 0; x[!i]; i ^= 1){
a[!i] -= x[i] / x[!i] * a[i];
x[i] = x[i] % x[!i];
}
return a[!i];
}ただしこれだと答えが正になったり負になったりするので,常に の範囲で値を得たいときは次のようにします.
int inverse(int mod, int val){
int x[2] = {mod, val};
int a[2] = {1, 0};
int i;
for(i = 0; x[!i]; i ^= 1){
a[!i] -= x[i] / x[!i] * a[i];
x[i] = x[i] % x[!i];
}
if(!i) a[!i] += mod;
return a[!i];
}この記事があなたの役に立てば幸いです.