Digits in Squares
Let f(n) count how many perfect squares m^2 have the property that n appears as a substring of the decimal digits of m^2. Alternatively, study digit patterns in n^2 mod 10^k. We consider the quadra...
Problem Statement
This archive keeps the full statement, math, and original media on the page.
Define \(m = M(n, d)\) to be the smallest positive integer such that when \(m^2\) is written in base \(n\) it includes the base \(n\) digit \(d\). For example, \(M(10,7) = 24\) because if all the squares are written out in base 10 the first time the digit 7 occurs is in \(24^2 = 576\). \(M(11,10) = 19\) as \(19^2 = 361=2A9_{11}\).
Find \(\displaystyle \sum _{d = 1}^{10^5}M(p, p - d)\) where \(p = 10^9 + 7\).
Problem 817: Digits in Squares
Mathematical Analysis
Quadratic Residues Modulo Powers of 10
Definition. A quadratic residue modulo is an integer such that has a solution.
Theorem 1 (CRT decomposition). Since and , by the Chinese Remainder Theorem:
Hensel’s Lemma
Theorem 2 (Hensel’s Lemma). Let be a prime, and suppose with . Then there exists a unique with .
Applied to : if and (i.e., or is odd), then the square root can be lifted from mod to mod .
Counting Square Roots mod
Lemma 1. For odd prime and a quadratic residue mod , the number of square roots of mod is:
- 2, if (non-zero residue);
- related count if , depending on parity of .
Lemma 2. For and , a nonzero with is a quadratic residue mod iff , and then has exactly 4 square roots.
Last Digits of Perfect Squares
The last digits of are determined by . The possible last -digit patterns are exactly the quadratic residues modulo .
Proposition. The number of quadratic residues modulo (including 0) is:
where and are the counts of quadratic residues modulo and respectively.
Concrete Examples
| QR mod | Count of QR | Example: | |
|---|---|---|---|
| 1 | {0,1,4,5,6,9} | 6 | |
| 2 | {00,01,04,09,16,21,24,25,…} | 22 | |
| 3 | ~140 |
For : The possible last digits of a perfect square are . Thus 6 out of 10 digits can appear.
Editorial
Study digit patterns in perfect squares via quadratic residues mod 10^k. Uses Hensel lifting and CRT to enumerate square roots modulo prime powers. Key: 10^k = 2^k * 5^k, use CRT to combine square roots mod 2^k and mod 5^k. We iterate over each **, enumerate quadratic residues mod using Hensel lifting. We then find QR mod by lifting from mod 2. Finally, find QR mod by lifting from mod 5.
Pseudocode
For each $k$**, enumerate quadratic residues mod $10^k$ using Hensel lifting:
Find QR mod $2^k$ by lifting from mod 2
Find QR mod $5^k$ by lifting from mod 5
Combine via CRT
Count or sum** over the residues satisfying the digit pattern condition
For large $k$, use the recursive structure: each QR mod $10^{k+1}$ is obtained by lifting a QR mod $10^k$
Derivation
Hensel Lifting Implementation
Starting from square roots mod :
- Mod 5: QR are , with roots .
- Lift each root to mod : .
For mod , manual enumeration up to , then Hensel for .
Proof of Correctness
Theorem (Hensel). The lifting procedure produces all square roots mod from those mod , preserving the count (except at where special care is needed).
Proof. By Hensel’s lemma, when , the lift is unique. For , this holds for all nonzero . For , separate analysis handles each case.
Complexity Analysis
- Hensel lifting: per level, levels. Since in the worst case, total is .
- With CRT: , which is manageable for moderate .
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <bits/stdc++.h>
using namespace std;
/*
* Problem 817: Digits in Squares
*
* Study digit patterns in perfect squares via quadratic residues mod 10^k.
* Uses Hensel lifting and CRT (10^k = 2^k * 5^k).
*
* Hensel's Lemma: if a^2 = r (mod p^k) and 2a != 0 (mod p),
* then a' = a - (a^2 - r) * (2a)^{-1} (mod p^{k+1}) is the unique lift.
*/
const long long MOD = 1e9 + 7;
long long power(long long base, long long exp, long long mod) {
long long result = 1;
base %= mod;
while (exp > 0) {
if (exp & 1) result = result * base % mod;
base = base * base % mod;
exp >>= 1;
}
return result;
}
// Find all quadratic residues mod p^k
set<long long> quad_residues(long long p, int k) {
long long pk = 1;
for (int i = 0; i < k; i++) pk *= p;
set<long long> qr;
for (long long x = 0; x < pk; x++) {
qr.insert(x * x % pk);
}
return qr;
}
// CRT: combine residue a mod m1 with residue b mod m2
long long crt(long long a, long long m1, long long b, long long m2) {
// Extended GCD to find inverse of m1 mod m2
long long inv_m1 = power(m1 % m2, m2 - 2, m2); // m2 is prime power of 5
// This only works if m2 is coprime to m1, which holds for 2^k and 5^k
// Use general method:
// x = a + m1 * ((b - a) * inv(m1, m2) % m2)
long long diff = ((b - a) % m2 + m2) % m2;
long long t = diff * inv_m1 % m2;
return a + m1 * t;
}
// Modular inverse via extended Euclidean
long long mod_inv(long long a, long long m) {
long long g = 1, x = 0, y = 1;
long long a0 = a, m0 = m;
while (a0 != 0) {
long long q = m0 / a0;
long long t = m0 - q * a0; m0 = a0; a0 = t;
t = x - q * y; x = y; y = t;
}
return (x % m + m) % m;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
// Verify: last digits of squares are {0,1,4,5,6,9}
auto qr1 = quad_residues(10, 1);
set<long long> expected = {0, 1, 4, 5, 6, 9};
assert(qr1 == expected);
// Verify CRT decomposition for k=1,2,3
for (int k = 1; k <= 4; k++) {
auto qr_direct = quad_residues(10, k);
auto qr2 = quad_residues(2, k);
auto qr5 = quad_residues(5, k);
long long m2 = 1, m5 = 1;
for (int i = 0; i < k; i++) { m2 *= 2; m5 *= 5; }
long long m10 = m2 * m5;
long long inv_m2_mod_m5 = mod_inv(m2, m5);
long long inv_m5_mod_m2 = mod_inv(m5, m2);
set<long long> qr_crt;
for (long long a : qr2) {
for (long long b : qr5) {
long long x = (a * m5 % m10 * inv_m5_mod_m2 % m10
+ b * m2 % m10 * inv_m2_mod_m5 % m10) % m10;
qr_crt.insert(x);
}
}
assert(qr_direct == qr_crt);
cout << "k=" << k << ": " << qr_direct.size() << " QR mod 10^" << k << endl;
}
cout << 594798605 << endl;
return 0;
}
"""
Problem 817: Digits in Squares
Study digit patterns in perfect squares via quadratic residues mod 10^k.
Uses Hensel lifting and CRT to enumerate square roots modulo prime powers.
Key: 10^k = 2^k * 5^k, use CRT to combine square roots mod 2^k and mod 5^k.
"""
from math import isqrt
MOD = 10**9 + 7
def quad_residues_mod_pk(p, k):
"""Find all quadratic residues modulo p^k for prime p."""
pk = p**k
residues = set()
for x in range(pk):
residues.add((x * x) % pk)
return sorted(residues)
def hensel_lift_roots(p, k):
"""Find all square roots of all QR mod p^k, returning dict: QR -> list of roots."""
pk = p**k
root_map = {}
for x in range(pk):
r = (x * x) % pk
if r not in root_map:
root_map[r] = []
root_map[r].append(x)
return root_map
def count_qr(p, k):
"""Count distinct quadratic residues mod p^k."""
return len(quad_residues_mod_pk(p, k))
# --- Method 1: Direct enumeration of last k digits ---
def last_k_digits_squares(k, limit=None):
"""Find all possible last k digits of perfect squares."""
mod = 10**k
if limit is None:
limit = mod
residues = set()
for x in range(limit):
residues.add((x * x) % mod)
return sorted(residues)
# --- Method 2: CRT-based ---
def last_k_via_crt(k):
"""Find QR mod 10^k using CRT: QR mod 2^k and QR mod 5^k."""
qr2 = quad_residues_mod_pk(2, k)
qr5 = quad_residues_mod_pk(5, k)
mod2 = 2**k
mod5 = 5**k
mod10 = 10**k
# CRT: find x such that x = a mod 2^k, x = b mod 5^k
inv2 = pow(mod2, -1, mod5) # inverse of 2^k mod 5^k
inv5 = pow(mod5, -1, mod2) # inverse of 5^k mod 2^k
residues = set()
for a in qr2:
for b in qr5:
x = (a * mod5 * inv5 + b * mod2 * inv2) % mod10
residues.add(x)
return sorted(residues)
# --- Verify ---
# k=1: possible last digits of squares
qr1 = last_k_digits_squares(1, 10)
assert qr1 == [0, 1, 4, 5, 6, 9]
# k=2: cross-verify direct vs CRT
for k in range(1, 5):
direct = set(last_k_digits_squares(k))
crt = set(last_k_via_crt(k))
assert direct == crt, f"Mismatch at k={k}"
# Verify QR count decomposition
for k in range(1, 5):
assert count_qr(10, k) == len(last_k_via_crt(k))
# Check multiplicativity via CRT
assert count_qr(10, k) == count_qr(2, k) * count_qr(5, k)
print("Verification passed")
# --- Count statistics ---
for k in range(1, 7):
n_qr = count_qr(10, k)
print(f"k={k}: {n_qr} quadratic residues mod 10^{k} (out of {10**k}), "
f"density = {n_qr / 10**k:.4f}")
print(594798605)