Cyclical Figurate Numbers
Triangle, square, pentagonal, hexagonal, heptagonal, and octagonal numbers are all figurate (polygonal) numbers generated by: | Type | Formula | Sequence | |------|---------|----------| | Triangle...
Problem Statement
This archive keeps the full statement, math, and original media on the page.
Triangle, square, pentagonal, hexagonal, heptagonal, and octagonal numbers are all figurate (polygonal) numbers and are generated by the following formulae:
| Triangle | $P_{3, n} = n(n + 1)/2$ | $1, 3, 6, 10, 15, \ldots$ |
| Square | $P{4, n} = n^2$ | $1, 4, 9, 25, \ldots$ |
| Pentagonal | $P_{5, n} = n(3n - 1)/2$ | $1, 5, 12, 22, 35, \ldots$ |
| Henxagonal | $P_{6, n} = n(2n - 1)/2$ | $1, 6, 15, 28, 45, \ldots$ |
| Heptagonal | $P_{7, n} = n(5n - 3)/2$ | $1, 7, 18, 34, 55, \ldots$ |
| Octangonal | $P_{8, n} = n(3n - 2)$ | $1, 8, 21, 40, 65, \ldots$ |
The ordered set of three $4$-digit numbers: $8128$, $2882$, $8281$, has three interesting properties.
The set is cyclic, in that the last two digits of each number is the first two digits of the next number (including the last number with the first).
Each polygonal type: triangle ($P_{3,127}=8128$), square ($P_{4,91}=8281$), and pentagonal ($P_{5,44}=2882$), is represented by a different number in the set.
This is the only set of $4$-digit numbers with this property.
Find the sum of the only ordered set of six cyclic $4$-digit numbers for which each polygonal type: triangle, square, pentagonal, hexagonal, heptagonal, and octagonal, is represented by a different number in the set.
Problem 61: Cyclical Figurate Numbers
Mathematical Foundation
Definition 1. The -gonal number of order is defined as
Theorem 1 (Closed form for polygonal numbers). The formula in Definition 1 satisfies for all , and the recurrence for .
Proof. Verification of the initial condition: . For the recurrence, compute
Simplifying: . This matches the defining property that consecutive differences of -gonal numbers form an arithmetic progression with common difference .
Lemma 1 (Index bounds for 4-digit polygonal numbers). For each , the indices producing 4-digit values form a contiguous range :
| Count | |||
|---|---|---|---|
| 3 | 45 | 140 | 96 |
| 4 | 32 | 99 | 68 |
| 5 | 26 | 81 | 56 |
| 6 | 23 | 70 | 48 |
| 7 | 21 | 63 | 43 |
| 8 | 19 | 58 | 40 |
Proof. Since is a strictly increasing function of for (each successive difference ), the set is a contiguous integer interval. The endpoints are obtained by solving the quadratic :
taking the positive root. Then and . Direct evaluation confirms the table entries.
Definition 2 (Cyclic linking). A 4-digit number links to another 4-digit number if , i.e., the last two digits of equal the first two digits of . Both the suffix and the prefix must lie in for meaningful two-digit linking.
Theorem 2 (Graph formulation). Define a directed labeled multigraph where:
- (the 90 possible two-digit prefixes/suffixes),
- For each 4-digit polygonal number of type with and , include the directed edge with label and weight .
Then a valid solution to the problem corresponds to a directed 6-cycle in whose edges carry all six distinct labels .
Proof. Let be a valid cyclic set. Define . The cyclic condition (indices modulo 6) means each corresponds to the edge . Each has a unique polygonal type, giving six distinct edge labels. Conversely, any such 6-cycle in with all six labels yields a valid solution by reading off the edge weights.
Theorem 3 (Uniqueness). The solution is unique up to cyclic rotation.
Proof. By exhaustive depth-first search over with backtracking, starting from every possible initial edge and exploring all label-valid extensions, exactly one equivalence class of 6-cycles (under cyclic rotation) is found. The completeness of depth-first search with backtracking guarantees that no valid cycle is missed.
Editorial
We first enumerate all 4-digit polygonal numbers of types through and keep only those whose last two digits form a valid two-digit suffix. Each remaining number is then treated as a labeled link from its first two digits to its last two digits. Starting from every possible value, we perform a depth-first backtracking search that extends the chain only through matching suffix-prefix links and polygonal types that have not yet been used. A candidate is accepted only when it contains six values, uses all six types exactly once, and closes back to its starting prefix.
Pseudocode
Generate the 4-digit polygonal numbers of each required type.
Ignore any value whose final two digits do not form a valid link.
Organize the remaining values by polygonal type and by their first two digits.
For each possible starting value:
begin a chain containing only that value
mark its polygonal type as used
try to extend the chain recursively
During the recursive search:
if the chain already contains six values:
accept it only when the current suffix matches the opening prefix
otherwise, for each polygonal type not yet used:
inspect the values of that type whose prefix matches the current suffix
extend the chain by each such value in turn
Return the sum of the first chain that closes cyclically.
Complexity Analysis
Time: Let be the total number of valid edges. The DFS explores at most paths from each starting edge, where is the branching factor at depth . Since the label-uniqueness constraint eliminates at least one type per level and the average out-degree per vertex is , the effective search space is small. The overall worst-case bound is , which evaluates to a constant for this problem size.
Space: for the adjacency lists, plus for the DFS recursion stack. Total: .
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <bits/stdc++.h>
using namespace std;
int main() {
// P(s,n) = n * ((s-2)*n - (s-4)) / 2
auto polygonal = [](int s, int n) -> int {
return n * ((s - 2) * n - (s - 4)) / 2;
};
// Generate all 4-digit polygonal numbers for types 3..8
vector<vector<int>> poly(6);
for (int s = 3; s <= 8; s++) {
for (int n = 1; ; n++) {
int val = polygonal(s, n);
if (val >= 10000) break;
if (val >= 1000 && val % 100 >= 10)
poly[s - 3].push_back(val);
}
}
// Build adjacency: by_prefix[type][prefix] = list of (suffix, value)
vector<unordered_map<int, vector<pair<int,int>>>> by_prefix(6);
for (int t = 0; t < 6; t++)
for (int v : poly[t]) {
int p = v / 100, s = v % 100;
by_prefix[t][p].push_back({s, v});
}
// DFS to find 6-cycle using all six types
int answer = 0;
int chain[6];
function<void(int, int, int, int)> dfs =
[&](int depth, int used_mask, int cur_suffix, int start_prefix) {
if (answer) return;
if (depth == 6) {
if (cur_suffix == start_prefix) {
int sum = 0;
for (int i = 0; i < 6; i++) sum += chain[i];
answer = sum;
}
return;
}
for (int t = 0; t < 6; t++) {
if (used_mask & (1 << t)) continue;
auto it = by_prefix[t].find(cur_suffix);
if (it == by_prefix[t].end()) continue;
for (auto& [suf, val] : it->second) {
chain[depth] = val;
dfs(depth + 1, used_mask | (1 << t), suf, start_prefix);
if (answer) return;
}
}
};
for (int t = 0; t < 6 && !answer; t++)
for (int v : poly[t]) {
int p = v / 100, s = v % 100;
chain[0] = v;
dfs(1, 1 << t, s, p);
if (answer) break;
}
cout << answer << endl;
return 0;
}
"""
Problem 61: Cyclical Figurate Numbers
Find the sum of the only ordered set of six cyclic 4-digit numbers
for which each polygonal type (triangle through octagonal) is represented.
"""
from collections import defaultdict
def polygonal(s, n):
"""Return the n-th s-gonal number: P(s,n) = n*((s-2)*n - (s-4)) / 2."""
return n * ((s - 2) * n - (s - 4)) // 2
def solve():
# Generate 4-digit polygonal numbers for each type s in {3,...,8}
poly = [[] for _ in range(6)] # index 0..5 for types 3..8
for s in range(3, 9):
n = 1
while True:
val = polygonal(s, n)
if val >= 10000:
break
if val >= 1000 and val % 100 >= 10:
poly[s - 3].append(val)
n += 1
# Build adjacency: by_prefix[type][prefix] -> list of (suffix, value)
by_prefix = [defaultdict(list) for _ in range(6)]
for t in range(6):
for v in poly[t]:
p, s = divmod(v, 100)
by_prefix[t][p].append((s, v))
# DFS to find a 6-cycle using all six types
def dfs(depth, used_mask, cur_suffix, start_prefix, chain):
if depth == 6:
if cur_suffix == start_prefix:
return sum(chain)
return None
for t in range(6):
if used_mask & (1 << t):
continue
for suf, val in by_prefix[t].get(cur_suffix, []):
result = dfs(depth + 1, used_mask | (1 << t),
suf, start_prefix, chain + [val])
if result is not None:
return result
return None
# Try starting with each type and each number
for t in range(6):
for v in poly[t]:
p, s = divmod(v, 100)
result = dfs(1, 1 << t, s, p, [v])
if result is not None:
return result
answer = solve()
assert answer == 28684
print(answer)