Problem 743: Window into a Matrix
View on Project EulerProject Euler Problem 743 Solution
EulerSolve provides an optimized solution for Project Euler Problem 743, Window into a Matrix, with C++, Python, Java, and a step-by-step mathematical explanation.
Problem Summary This problem asks for the quantity \(A(k,n)\) arising from the matrix setup, under the condition \(k\mid n\), with the final value taken modulo \(M=10^9+7\). The concrete target is extremely large, so the essential task is to turn the definition into a summation that can be streamed term by term rather than expanded combinatorially from scratch. The C++, Python, and Java implementations all reveal the same structure: once we write \(q=n/k\) and reduce \(2^q\) modulo \(M\), the whole computation becomes a weighted central-trinomial-type sum whose consecutive terms differ by a simple rational factor. Mathematical Approach Throughout the derivation let $M=10^9+7,\qquad q=\frac{n}{k},\qquad b=2^q \pmod{M}.$ The implementations do not build the answer from factorial tables. Instead they exploit a closed form for the summand and a recurrence between neighboring terms. Step 1: Rewrite the target as a weighted constant term Modulo \(M\), a convenient reformulation is $A(k,n)\equiv [z^0]\,(b+z+z^{-1})^k \pmod{M},$ where \([z^0]\) means the coefficient of \(z^0\). To contribute to the constant term, an expansion term must contain the same number of \(z\) and \(z^{-1}\) factors. If we choose exactly \(x\) copies of \(z\) and \(x\) copies of \(z^{-1}\), then the remaining \(k-2x\) factors contribute \(b\)....
Detailed mathematical approach
Problem Summary
This problem asks for the quantity \(A(k,n)\) arising from the matrix setup, under the condition \(k\mid n\), with the final value taken modulo \(M=10^9+7\). The concrete target is extremely large, so the essential task is to turn the definition into a summation that can be streamed term by term rather than expanded combinatorially from scratch.
The C++, Python, and Java implementations all reveal the same structure: once we write \(q=n/k\) and reduce \(2^q\) modulo \(M\), the whole computation becomes a weighted central-trinomial-type sum whose consecutive terms differ by a simple rational factor.
Mathematical Approach
Throughout the derivation let
$M=10^9+7,\qquad q=\frac{n}{k},\qquad b=2^q \pmod{M}.$
The implementations do not build the answer from factorial tables. Instead they exploit a closed form for the summand and a recurrence between neighboring terms.
Step 1: Rewrite the target as a weighted constant term
Modulo \(M\), a convenient reformulation is
$A(k,n)\equiv [z^0]\,(b+z+z^{-1})^k \pmod{M},$
where \([z^0]\) means the coefficient of \(z^0\). To contribute to the constant term, an expansion term must contain the same number of \(z\) and \(z^{-1}\) factors. If we choose exactly \(x\) copies of \(z\) and \(x\) copies of \(z^{-1}\), then the remaining \(k-2x\) factors contribute \(b\).
This gives the explicit sum
$A(k,n)=\sum_{x=0}^{\lfloor k/2\rfloor}\frac{k!}{x!^2(k-2x)!}\,b^{k-2x}\pmod{M}.$
An equivalent binomial form is
$A(k,n)=\sum_{x=0}^{\lfloor k/2\rfloor}\binom{k}{2x}\binom{2x}{x}b^{k-2x}\pmod{M}.$
This is why the sequence behaves like a weighted version of the central trinomial coefficients.
Step 2: Derive the ratio between consecutive terms
Define
$T_x=\frac{k!}{x!^2(k-2x)!}\,b^{k-2x}\pmod{M}.$
Then \(A(k,n)=\sum_x T_x\). The key simplification is that \(T_x\) can be obtained from \(T_{x-1}\) without recomputing any factorials:
$\frac{T_x}{T_{x-1}}=\frac{(k-2x+2)(k-2x+1)}{x^2}\,b^{-2}.$
The factorial part collapses because
$\frac{(x-1)!^2(k-2x+2)!}{x!^2(k-2x)!}=\frac{(k-2x+2)(k-2x+1)}{x^2},$
and the power of \(b\) drops by two at every step. Therefore
$T_x=T_{x-1}\cdot \frac{(k-2x+2)(k-2x+1)}{x^2}\cdot b^{-2}\pmod{M},$
starting from
$T_0=b^k.$
Step 3: Replace divisions with modular inverses
Because \(M\) is prime and \(b=2^q\) is nonzero modulo \(M\), every required division can be turned into multiplication by an inverse. Fermat's little theorem gives
$a^{-1}\equiv a^{M-2}\pmod{M}$
for any nonzero \(a\). In particular, the implementations compute \(b^{-1}\) as \(b^{M-2}\) and then square it once to get the fixed multiplier \(b^{-2}\).
They also need \(x^{-1}\) for all \(1\le x\le \lfloor k/2\rfloor\). Rather than calling fast exponentiation for each \(x\), they precompute inverses in linear time using
$\operatorname{inv}(1)=1,\qquad \operatorname{inv}(i)=M-\left\lfloor\frac{M}{i}\right\rfloor \operatorname{inv}(M\bmod i)\pmod{M}.$
Then the factor \(x^{-2}\) becomes two multiplications by \(\operatorname{inv}(x)\).
Step 4: Stream the whole sum in one pass
A direct factorial-based method would require large factorial and inverse-factorial tables up to \(k\), which is unnecessary here. The ratio formula reduces the update at step \(x\) to five ingredients: the previous term, two descending numerator factors, two copies of \(x^{-1}\), and the constant factor \(b^{-2}\).
So the computation can march from \(x=0\) to \(x=\lfloor k/2\rfloor\), updating the current term and adding it to the running total immediately. Nothing from earlier terms needs to be revisited.
Step 5: Worked Example
For the checkpoint \(A(3,9)\), we have
$q=\frac{9}{3}=3,\qquad b=2^3=8.$
Since \(\lfloor 3/2\rfloor=1\), the sum has only two terms:
$T_0=b^3=8^3=512,$
$T_1=\frac{3!}{1!^2\,1!}b^{1}=6\cdot 8=48.$
Hence
$A(3,9)=512+48=560,$
matching the checkpoint used by the implementation. A second checkpoint is
$A(4,20)=32^4+12\cdot 32^2+6=1{,}060{,}870.$
How the Code Works
The C++, Python, and Java implementations all follow the same algorithm. First they compute \(q=n/k\), then evaluate \(b=2^q\pmod{M}\) by fast modular exponentiation, and finally initialize the first summand as \(b^k\pmod{M}\). The running answer starts from that same initial term.
Next they compute the inverse of \(b\), square it to obtain \(b^{-2}\), and build an inverse table for the integers \(1\) through \(\lfloor k/2\rfloor\). During the main loop, the implementation updates the current summand by multiplying with the next two descending numerator factors, the inverse of the current index twice, and the fixed factor \(b^{-2}\). The new summand is then added to the running total modulo \(M\).
This approach avoids storing factorial arrays, inverse-factorial arrays, or any large polynomial object. The code keeps only the current summand, the running total, the inverse table, and a few loop variables.
Complexity Analysis
Let \(h=\lfloor k/2\rfloor\). The modular exponentiations cost \(O(\log q+\log M)\) time, which is tiny compared with the main loop. Filling the inverse table costs \(O(h)\) time and \(O(h)\) memory, and the streaming summation also costs \(O(h)\) time. Therefore the full method runs in \(O(k)\) time and uses \(O(k)\) memory.
Footnotes and References
- Problem page: https://projecteuler.net/problem=743
- Central trinomial coefficient: Wikipedia - Central trinomial coefficient
- Binomial coefficient: Wikipedia - Binomial coefficient
- Modular multiplicative inverse: Wikipedia - Modular multiplicative inverse
- Fermat's little theorem: Wikipedia - Fermat's little theorem