From 6767453b4c52c808833fdeee8756ebbfe48d8878 Mon Sep 17 00:00:00 2001 From: terry_u16 Date: Fri, 18 Sep 2020 19:26:44 +0900 Subject: [PATCH] #54 Add modint.md --- document_ja/modint.md | 180 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 document_ja/modint.md diff --git a/document_ja/modint.md b/document_ja/modint.md new file mode 100644 index 00000000..7d33fdc1 --- /dev/null +++ b/document_ja/modint.md @@ -0,0 +1,180 @@ +# ModInt + +自動でmodを取る構造体です。パフォーマンスの都合上、`StaticModInt`と`DynamicModInt`の2種類が用意されています。それぞれの特徴は以下の通りです。 + +|型 |パフォーマンス|modを決定するタイミング |`T`の型(後述)| +|------------------|-------------|--------------------------------|--------------| +|`StaticModInt` |良い |コンパイル時に決定している必要がある|`IStaticMod` | +|`DynamicModInt`|やや劣る |実行時でもよい |`IDynamicModID`| + +実行時にならないとmodが決定できない一部のケースを除き、`StaticModInt`の使用を推奨します。 + +## 基本的な使い方 + +### StaticModInt<T> + +型引数`T`に`Mod1000000007`または`Mod998244353`のいずれかを設定します。`using`を用いて別名を付けると便利です。 + +それ以外のmodの設定方法については、Tipsをご参照ください。 + +```C# +using System; +using ModInt = AtCoder.StaticModInt; // ModIntという別名を付ける + +void StaticModIntTest() +{ + var a = new ModInt(100000); + var b = new ModInt(100000); + + var add = a + b; + var sub = a - b; + var mul = a * b; + var div = a / b; + + Console.WriteLine(add); // 200000 + Console.WriteLine(sub); // 0 + Console.WriteLine(mul); // 999999937 + Console.WriteLine(div); // 1 +} +``` + +### DynamicModInt<T> + +型引数`T`に`ModID0`, `ModID1`, `ModID2`のいずれかを設定します。C++版と同様、ID別にmodを設定できます。 + +IDを4つ以上使い分けたい場合の設定方法については、Tipsをご参照ください。 + +```C# +using System; +using ModInt = AtCoder.DynamicModInt; // ModIntという別名を付ける + +void DynamicModIntTest() +{ + ModInt.Mod = 1000000009; // mod 1000000009に設定 + var a = new ModInt(100000); + var b = new ModInt(100000); + + var add = a + b; + var sub = a - b; + var mul = a * b; + var div = a / b; + + Console.WriteLine(add); // 200000 + Console.WriteLine(sub); // 0 + Console.WriteLine(mul); // 999999919 + Console.WriteLine(div); // 1 +} +``` + +## メンバー + +以下に示すメソッドおよびプロパティは、`DynamicModInt.Mod`を除き、`StaticModInt`と`DynamicModInt`のどちらでも同じように使えます。以下、便宜上`StaticModInt`と`DynamicModInt`をまとめて`ModInt`と表記します。 + +基本的にC++版ACLと使い方は同様ですので、詳細については[そちらのドキュメント](https://atcoder.github.io/ac-library/document_ja/modint.html)をお読みください。C++版とC#版の対応表を以下に示します。 + +|C++版|C#版| +|-----|-----| +|`modint x()`|`new ModInt()`| +|`modint x(T y)`|`new ModInt(long y)`| +|`modint::set_mod(int m)`|`DynamicModInt.Mod`| +|`modint::mod()`|`DynamicModInt.Mod`| +|`x.val();`|`x.Value`| +|`-x`|`-x`| +|`x++`|`x++`| +|`x--`|`x--`| +|`++x`|`++x`| +|`--x`|`--x`| +|`x + y`|`x + y`| +|`x - y`|`x - y`| +|`x * y`|`x * y`| +|`x / y`|`x / y`| +|`x += y`|`x += y`| +|`x -= y`|`x -= y`| +|`x *= y`|`x *= y`| +|`x /= y`|`x /= y`| +|`x == y`|`x == y`| +|`x != y`|`x != y`| +|`x.pow(ll n)`|`x.Pow(long n)`| +|`x.inv()`|`x.Inv()`| +|`modint::raw(int x)`|`ModInt.Raw(int x)`| + +## Tips + +### 1000000007, 998244353以外のmod設定方法 + +`StaticModInt`には、型引数`T`として`IStaticMod`を実装した構造体を渡すことができます。`IStaticMod`は以下のような定義となっており、`Mod`プロパティ(modの値)と`IsPrime`プロパティ(modが素数かどうか)を持ちます。 + +```C# +public interface IStaticMod +{ + uint Mod { get; } + bool IsPrime { get; } +} +``` + +よく使われるmodとしてあらかじめ`Mod1000000007`および`Mod998244353`が用意されていますが、それ以外のmodを使いたい場合、以下のような構造体を自作して`StaticModInt`に渡せばよいです。`DynamicModInt.Mod`にmodを設定する方法と比べ、高速に動作します。 + +```C# +public struct Mod13 : IStaticMod +{ + public uint Mod => 13; + public bool IsPrime => true; +} + +void OtherModTest() +{ + var x = new StaticModInt(20); + + Console.WriteLine(x); // 7 +} +``` + +### 4種類以上のDynamicModInt<T>の使い分け + +`DynamicModInt`には、型引数`T`として`IDynamicModID`を実装した構造体を渡すことができます。`IDynamicModID`は以下のような定義を持つ空のインターフェースです。 + +```C# +public interface IDynamicModID { } +``` + +デフォルトで`ModID0`, `ModID1`, `ModID2`の3種類が用意されていますが、4種類以上の`DynamicModInt`を使い分けたい場合、以下のような構造体を自作して`DynamicModInt`に渡せばよいです。 + +```C# +public struct ModID3 : IDynamicModID { } + +void MultipleModTest() +{ + DynamicMod.Mod = 2; + DynamicMod.Mod = 3; + DynamicMod.Mod = 5; + DynamicMod.Mod = 7; + + var a = new DynamicModInt(13); + var b = new DynamicModInt(13); + var c = new DynamicModInt(13); + var d = new DynamicModInt(13); + + Console.WriteLine(a); // 1 + Console.WriteLine(b); // 1 + Console.WriteLine(c); // 3 + Console.WriteLine(d); // 6 +} +``` + +なお、IDが異なるmod同士の計算はできません。 + +### 暗黙的な型変換 + +`ModInt`と他の整数型(`int`型等)を計算する場合、自動で`ModInt`型に変換されます。 + +```C# +var x = new ModInt(10); +var y = x + 1; // var y = x + new ModInt(1); と同じ +``` + +また、`ToString()`がオーバーライドされており、`Console.WriteLine()`等に渡した場合は`Value`の値が表示されます。 + +```C# +var x = new ModInt(10); +Console.WriteLine(x); // 10 と表示される +```