Arpa's blog

By Arpa, history, 5 months ago, In English

Hello Codeforces!

I’m going to introduce you to a C++ struct that helps you easily forget MOD, instead of always being nervous about it.


Using this struct, you can easily add, subtract, multiply, divide, and raise to a power without thinking about overflow or missing MOD. Everything is considered in it. This is very easy to use; copy, paste, and use. Let’s see a few examples.

Operation Before After
Addition
(a + b) % MOD
a + b
Subtraction
(a — b + MOD) % MOD
a — b
Multiplication
a * b % MOD
a * b
Division Maybe a * raising b to power MOD — 2?
a / b
Power Implementing the binary pow function
a.pow(b)

Let's look at a real problem, 296B - Yaroslav and Two Strings. The following is the old solution (20869331) without using Mint:

int sbet = 1, pbet = 1, mos = 1;
for(int i = 0; i < n; i++)
    sbet = (ll) sbet * bet(s[i], p[i]) % mod,
        pbet = (ll) pbet * bet(p[i], s[i]) % mod,
        mos = (ll) mos * eq(p[i], s[i]) % mod;
int ans = 1;
int b = count(s.begin(), s.end(), '?') + count(p.begin(), p.end(), '?');
for(int a = 10; b; b >>= 1, a = (ll) a * a % mod)
    if(b & 1)
        ans = (ll) ans * a % mod;
(ans += mos) %= mod;
(ans -= sbet — mod) %= mod;
(ans -= pbet — mod)  %= mod;
cout << ans << '\n';

But now, see how clean the new version (351365035) is:

Mint sbet = 1, pbet = 1, mos = 1;
for (int i = 0; i < n; i++) {
    sbet *= bet(s[i], p[i]);
    pbet *= bet(p[i], s[i]);
    mos *= eq(p[i], s[i]);
}
Mint ans = Mint(10).pow(count(s.begin(), s.end(), '?') + count(p.begin(), p.end(), '?'));
cout << ans + mos - sbet - pbet << '\n';

More examples:

Benefits of the Mint struct:

  • You never need to use MOD in your code.
  • Operations with int and Mint are handled safely. Like 2 + x, x + 2, x / 2, all of them work.
  • Takes modulo only once, in its constructor.
  • Short, easy to implement if you want to type it (like in ICPC) or remember it.

Also, there is an appendix to the Mint struct which makes the factorials and comb function, which are useful in a lot of cases.

I've been using this for several years, and you can be sure it works fine.


Code here

If you want to copy/paste, use this.

  • Vote: I like it
  • +10
  • Vote: I do not like it

»
5 months ago, hide # |
 
Vote: I like it +72 Vote: I do not like it

Note that Codeforces parsed - in the code block as &mdash;, which is likely not what you want.

Some quick improvements:

  • For initialization, it might be better to do (x + SQUARE_MOD) % MOD, as % is expensive.
  • It's best to handle operators + and - without %, ideally like std::min<unsigned>(a+b, a+b-mod)
  • It may or may not be better to try avoiding % in constructor when x is already small...

Also, in some problems, typically involving factorization and stuff, you may need to work modulo several different numbers at once, and sometimes those numbers can be more than 32 bit, which is annoying as hell to work with.

I have modint<mod> and dynamic_modint<> in modint.hpp to handle these cases separately, the latter using Montgomery reduction for multiplication, as otherwise compiler would not be able to optimize % when it's done for a mod that is only known at runtime. That leads to some significant amount of code though, not sure what's the easiest way to handle it more concisely...

  • »
    »
    5 months ago, hide # ^ |
     
    Vote: I like it -21 Vote: I do not like it

    Thanks for mentioning issues and your modints.

    The main objective of my implementation is simplicity. I know it's not fast enough (I got TLE once out of hundreds of times I used this struct), but it's very simple.

»
5 months ago, hide # |
 
Vote: I like it +8 Vote: I do not like it
»
5 months ago, hide # |
Rev. 2  
Vote: I like it -8 Vote: I do not like it

Here's my template, which supports 64bit arithmetic, combinatorics, square roots and i/o (still not perfect): link