0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

競プロででてくる剰余の演算のメモ

Posted at

剰余演算に関して

atcoderでたまに見かける答えに剰余を解答にする問題を見る。
競プロと剰余の記事としてはこの辺がまとまっている。
https://qiita.com/drken/items/3b4fdf0a78e7a138cd9a
大きな値はとれないので剰余にしていると思われるが、計算でよく使う分配則が本当に成り立つのかとか
これマイナスになったらどうすんの?という疑問があった

剰余はこれ
https://ja.wikipedia.org/wiki/%E5%89%B0%E4%BD%99%E6%BC%94%E7%AE%97
問題の一例はこれ
https://atcoder.jp/contests/abc178/tasks/abc178_c

剰余の分配則について

剰余の分配則はwikiの分配則参照してほしいがよく使うのは以下の式

(a+b) \bmod n = ((a\bmod n) +(b \bmod n))\bmod n

ちなみに分配則の証明は調べても出てこない。なんとなくmodの定義見てたら
いいかなという気になります。

n個の場合に成り立ちそうかどうかはここにある
https://pokuwagata.hatenablog.com/entry/2020/08/30/134727

剰余の分配則で負の値をとってしまう場合

引き算したときには分配則の左辺と右辺が異なる場合がある。 a=4,b=-3,n=2として分配則に適用すると


(a+b) \bmod n =(4-3) \bmod 2 = 1 \\
((a\bmod n) +(b \bmod n))\bmod n=((4\bmod 2) -(3 \bmod 2))\bmod 2 = (0 - 1)\bmod2 = -1  

となる(上段が分配則の左辺、下段が右辺)。
bがそもそも負の数をとってはいかんのだがそれはさておき競プロでは剰余にした結果
そういう計算が生じることもある。今回の問題なんかはそれである。
さて、どう対策するかというと解答を見てみるとどうやら

(a-b) \bmod n = ((a - b)\bmod n + n) \bmod n 

が成り立ちそうな気配である。

\begin{align}
((a - b)\bmod n + n) \bmod n &= ((a-b) \bmod n + n \bmod n) \bmod n\\
&=((a-b) \bmod n) \bmod n \\
&=(a-b) \bmod n
\end{align}

確かに成り立ちそう。
求めたいのは最終行だがそのまま分配則で計算すると上の例の通りマイナスになってしまうため
nを足してあげているということだ。誰が考え付いたのかわからんが有り難く使わせてもらう。

オーバーフローする値の剰余を求めるとき

簡単に言うとpythonのpowなんかでは問題がでないが素直にコーティングするとオーバーフローするやつである
https://qiita.com/R_olldIce/items/ab3f382643e92122f8ef
↑はpythonのpowの話

例えば10^45の剰余をとろうとする

fn main() {
let x: i32 = 10; // or any other integer type
println!("{}",x.pow(45 as u32) % 3);
}

これはもうエラーである(thread 'main' panicked at 'attempt to multiply with overflow'~)
ここで出てくるのが二分累乗法という方法です。
原理はここ参照
https://qiita.com/drken/items/3b4fdf0a78e7a138cd9a#4-%E7%B4%AF%E4%B9%97-an

rustでは以下のようになります(binary_poweringで実装)
https://zenn.dev/yuucu/scraps/df5c890cd38777
からもらってきました

fn main() {
let x: i64 = 10; // or any other integer type
println!("{}",binary_powering(x,45,3) );
}

pub fn binary_powering(mut a: i64, mut n: i64, m: i64) -> i64 {
    let mut res = 1i64;
    let m = if m != 0 { Some(m) } else { None };
    while n > 0 {
        if n & 1 != 0 {
            res *= a;
            if let Some(m) = m {
                res %= m
            }
        }
        a *= a;
        if let Some(m) = m {
            a %= m;
        }
        n >>= 1;
    }
    res
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?