-
Notifications
You must be signed in to change notification settings - Fork 312
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Template for modulo operations #40
base: master
Are you sure you want to change the base?
Changes from 4 commits
eef3b7e
54ea14c
ccb5210
4766516
0a990ea
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
""" | ||
This template is useful for problems involving a prime modulo. | ||
The template contains a fast function for calculating a * b % MOD, | ||
as well as precalculating factorial, inverse factorial, modular inverse | ||
for all integers < maxN in O(maxN) time. | ||
With this template, one can for example quickly calculate n choose k mod MOD, | ||
or calculate matrix multiplication mod MOD. | ||
""" | ||
|
||
def fast_modder(MOD): | ||
""" Returns function modmul(a,b,c=0) that quickly calculates (a * b + c) % MOD, assuming 0 <= a,b < MOD """ | ||
import sys, platform | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm tempted to move this up, to the top of the file, even though this is specific. |
||
impl = platform.python_implementation() | ||
maxs = sys.maxsize | ||
if 'PyPy' in impl and MOD <= maxs and MOD ** 2 > maxs: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can actually check |
||
import __pypy__ | ||
intsub = __pypy__.intop.int_sub | ||
intmul = __pypy__.intop.int_mul | ||
intmulmod = __pypy__.intop.int_mulmod | ||
if MOD < 2**30 - 1000: | ||
MODINV = 1.0 / MOD | ||
def modmul(a, b, c=0): | ||
return (intsub(intmul(a,b), intmul(MOD, int(MODINV * a * b))) + c) % MOD | ||
else: | ||
def modmul(a, b, c=0): | ||
return (intmulmod(a, b, MOD) + c) % MOD | ||
else: | ||
def modmul(a, b, c=0): | ||
return (a * b + c) % MOD | ||
return modmul | ||
|
||
|
||
""" Precalculate factorial, modular inverse of factorial and modular inverse """ | ||
MOD = 10 ** 9 + 7 # needs to be prime! | ||
maxN = 10 ** 6 | ||
cheran-senthil marked this conversation as resolved.
Show resolved
Hide resolved
|
||
modmul = fast_modder(MOD) | ||
|
||
def mod_precalc(): | ||
cheran-senthil marked this conversation as resolved.
Show resolved
Hide resolved
|
||
""" Calculates fac, inv_fac and mod_inv for i < maxN in O(maxN) time """ | ||
assert maxN <= MOD | ||
|
||
fac = [1] * maxN | ||
for i in range(2, maxN): | ||
fac[i] = modmul(fac[i - 1], i) | ||
|
||
inv_fac = [pow(fac[-1], MOD - 2, MOD)] * maxN | ||
for i in reversed(range(1, maxN)): | ||
inv_fac[i - 1] = modmul(inv_fac[i], i) | ||
cheran-senthil marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
inv_mod = [modmul(inv_fac[i], fac[i - 1]) for i in range(maxN)] | ||
|
||
return fac, inv_fac, inv_mod | ||
|
||
fac, inv_fac, inv_mod = mod_precalc() | ||
|
||
""" Useful functions involving modulo """ | ||
|
||
def choose(n,k): | ||
""" Calculate n choose k in O(1) time """ | ||
if k < 0 or k > n: | ||
return 0 | ||
return modmul(modmul(fac[n], invfac[k]), invfac[n-k]) | ||
|
||
def matrix_modmul(A, B): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have something for this elsewhere, so let's remove that too. |
||
""" Multiplies matrices A and B, assuming 0 <= A[i][j], B[i][j] < MOD """ | ||
assert len(A[0]) == len(B) | ||
C = [] | ||
for Ai in A: | ||
tmp = [0] * len(B[0]) | ||
for k in range(len(B)): | ||
Aik = Ai[k] | ||
Bk = B[k] | ||
for j in range(len(Bk)): | ||
tmp[j] = modmul(Aik, Bk[j], tmp[j]) | ||
C.append(tmp) | ||
return C |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps call this
make_modmul
?