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]; }
この記事があなたの役に立てば幸いです.