Problem 651: Patterned Cylinders
View on Project EulerProject Euler Problem 651 Solution
EulerSolve provides an optimized solution for Project Euler Problem 651, Patterned Cylinders, with C++, Python, Java, and a step-by-step mathematical explanation.
Problem Summary Let \(F_1=F_2=1\). For each integer \(t\) from \(4\) to \(40\), we consider an \(F_{t-1}\times F_t\) array of cells indexed by two periodic coordinates. A symmetry may independently shift or reverse either coordinate, so two colorings are equivalent if one can be transformed into the other by those operations. Only colorings that use all \(t\) colors at least once are valid, and Problem 651 asks for the sum of all such orbit counts modulo \(10^9+7\). If \(A_q(r,s)\) denotes the number of valid equivalence classes with \(q\) colors and side lengths \(r\) and \(s\), then the target quantity is $$\sum_{t=4}^{40} A_t(F_{t-1},F_t)\pmod{10^9+7}.$$ A brute-force search over all colorings is hopeless, so the solution counts fixed colorings under symmetry classes and averages them with Burnside's lemma. Mathematical Approach The implementation solves a general instance first and only then applies it to consecutive Fibonacci sizes....
Detailed mathematical approach
Problem Summary
Let \(F_1=F_2=1\). For each integer \(t\) from \(4\) to \(40\), we consider an \(F_{t-1}\times F_t\) array of cells indexed by two periodic coordinates. A symmetry may independently shift or reverse either coordinate, so two colorings are equivalent if one can be transformed into the other by those operations. Only colorings that use all \(t\) colors at least once are valid, and Problem 651 asks for the sum of all such orbit counts modulo \(10^9+7\).
If \(A_q(r,s)\) denotes the number of valid equivalence classes with \(q\) colors and side lengths \(r\) and \(s\), then the target quantity is
$$\sum_{t=4}^{40} A_t(F_{t-1},F_t)\pmod{10^9+7}.$$
A brute-force search over all colorings is hopeless, so the solution counts fixed colorings under symmetry classes and averages them with Burnside's lemma.
Mathematical Approach
The implementation solves a general instance first and only then applies it to consecutive Fibonacci sizes. The key object is the periodic grid
$$X_{r,s}=\mathbb{Z}/r\mathbb{Z}\times \mathbb{Z}/s\mathbb{Z}.$$
Step 1: Describe the Symmetries on One Axis
For one periodic axis of length \(n\), the allowed symmetries are the affine maps
$$x\mapsto \sigma x+t \pmod n,\qquad \sigma\in\{1,-1\},\ t\in \mathbb{Z}/n\mathbb{Z}.$$
When \(n>2\), this set has \(2n\) elements; for \(n=1\) and \(n=2\) some maps coincide, so those small cases are handled separately by the implementation.
The maps with \(\sigma=1\) are pure shifts. If such a shift has order \(u\), then every orbit on that axis is a cycle of length \(u\), and there are \(n/u\) such cycles. The number of shifts of order \(u\) is \(\varphi(u)\), because
$$u=\frac{n}{\gcd(n,t)}$$
and exactly \(\varphi(u)\) offsets produce that order. So every divisor \(u\mid n\) contributes one shift class with multiplicity \(\varphi(u)\) and cycle profile
$$u^{\,n/u}.$$
The maps with \(\sigma=-1\) are reversals. Their cycle structure depends only on the parity of \(n\):
$$\begin{aligned} n\ \text{odd}&:\quad 1^1\,2^{(n-1)/2},\\ n\ \text{even, one half of the reversals}&:\quad 1^2\,2^{(n-2)/2},\\ n\ \text{even, the other half}&:\quad 2^{n/2}. \end{aligned}$$
This follows from the congruence \(2x\equiv t\pmod n\): for odd \(n\) it has one solution, for even \(n\) it has either two or zero solutions depending on the parity of \(t\).
Step 2: Apply Burnside's Lemma
Let \(\Gamma_r\) and \(\Gamma_s\) be the symmetry sets on the two axes. A coloring is a function
$$f:X_{r,s}\to \{1,2,\dots,q\}.$$
For \((g,h)\in \Gamma_r\times \Gamma_s\), let \(c(g,h)\) be the number of cycles of the induced permutation on the cell set \(X_{r,s}\). A coloring fixed by \((g,h)\) must be constant on each cycle, so the fixed colorings that use every color are exactly the surjections from a \(c(g,h)\)-element cycle set onto the \(q\) colors.
By inclusion-exclusion, that number is
$$\operatorname{Surj}(c,q)=\sum_{j=0}^{q}(-1)^j\binom{q}{j}(q-j)^c.$$
Therefore Burnside gives
$$A_q(r,s)=\frac{1}{|\Gamma_r|\,|\Gamma_s|}\sum_{g\in\Gamma_r}\sum_{h\in\Gamma_s}\operatorname{Surj}(c(g,h),q).$$
This formula is exact, but it becomes fast only after we compress group elements by cycle type.
Step 3: Count Cycles on the Product Grid
Suppose one symmetry on the first axis contains \(m_i\) cycles of length \(\ell_i\), and one symmetry on the second axis contains \(n_j\) cycles of length \(r_j\). On the Cartesian product of one \(\ell_i\)-cycle and one \(r_j\)-cycle, the action advances simultaneously around both cycles.
The orbit length is \(\operatorname{lcm}(\ell_i,r_j)\), so the \(\ell_i r_j\) points split into
$$\frac{\ell_i r_j}{\operatorname{lcm}(\ell_i,r_j)}=\gcd(\ell_i,r_j)$$
product cycles. Summing over all profile pairs yields
$$c(g,h)=\sum_{i}\sum_{j} m_i n_j\,\gcd(\ell_i,r_j).$$
This is the central formula used to turn two one-dimensional cycle profiles into the number of cycles on the full two-dimensional pattern.
Step 4: Compress Burnside by Symmetry Classes
All group elements with the same cycle profile contribute the same fixed-coloring count, so the Burnside sum can be rewritten over classes instead of individual symmetries.
For one axis of length \(n\), the implementation needs only
$$\tau(n)+O(1)$$
different profiles: one shift profile for each divisor of \(n\), plus one or two reversal profiles according to parity. The multiplicities of those profiles are \(\varphi(u)\) for shifts and the obvious parity-dependent counts for reversals.
This compression is why huge symmetry groups never need to be enumerated explicitly. In the actual Fibonacci inputs, the number of class pairs is tiny compared with the raw number of group elements.
Step 5: Worked Example \(\boldsymbol{A_2(2,3)=11}\)
This checkpoint appears in the implementation and is small enough to compute by hand.
For length \(2\), the axis has two classes:
$$1^2\ \text{with multiplicity }1,\qquad 2^1\ \text{with multiplicity }1.$$
For length \(3\), the axis has three classes:
$$1^3\ \text{with multiplicity }1,\qquad 3^1\ \text{with multiplicity }2,\qquad 1^1 2^1\ \text{with multiplicity }3.$$
Because \(q=2\), the surjection count simplifies to
$$\operatorname{Surj}(c,2)=2^c-2.$$
Using the product-cycle formula, the six class pairs give
$$\begin{aligned} c(1^2,1^3)&=6, & \operatorname{mult}&=1,\\ c(1^2,3^1)&=2, & \operatorname{mult}&=2,\\ c(1^2,1^1 2^1)&=4, & \operatorname{mult}&=3,\\ c(2^1,1^3)&=3, & \operatorname{mult}&=1,\\ c(2^1,3^1)&=1, & \operatorname{mult}&=2,\\ c(2^1,1^1 2^1)&=3, & \operatorname{mult}&=3. \end{aligned}$$
So the weighted Burnside numerator is
$$1\cdot 62+2\cdot 2+3\cdot 14+1\cdot 6+2\cdot 0+3\cdot 6=132.$$
The group sizes are \(|\Gamma_2|=2\) and \(|\Gamma_3|=6\), hence
$$A_2(2,3)=\frac{132}{2\cdot 6}=11.$$
Step 6: Apply the General Formula to Consecutive Fibonacci Sizes
Once the class-compressed Burnside count \(A_q(r,s)\) is available, Problem 651 simply evaluates it at
$$q=t,\qquad r=F_{t-1},\qquad s=F_t,\qquad 4\le t\le 40,$$
and accumulates the results modulo \(10^9+7\):
$$\boxed{\sum_{t=4}^{40} A_t(F_{t-1},F_t)\pmod{10^9+7}.}$$
How the Code Works
The C++, Python, and Java implementations all follow the same mathematical pipeline. First they build the binomial coefficients needed by the inclusion-exclusion formula and use fast modular exponentiation for the powers \((q-j)^c\).
For each of the two periodic lengths, the implementation factorizes the length, enumerates its divisors, converts divisor data into shift classes with multiplicities \(\varphi(u)\), and then appends the parity-dependent reversal classes. The tiny degenerate lengths \(1\) and \(2\) are treated explicitly.
Next the implementation loops over every pair of classes from the two axes. For each pair it computes the total cycle count by summing \(\gcd(\ell_i,r_j)\) across the profile entries. Many different class pairs lead to the same cycle count, so the value of \(\operatorname{Surj}(c,q)\) is cached and reused.
Each Burnside contribution is the class multiplicity product times the cached surjection count. After summing all contributions, the implementation divides by the group size using a modular inverse and adds the resulting orbit count to the running Fibonacci total.
Complexity Analysis
For one general instance \(A_q(r,s)\), factorizing the two side lengths by trial division costs \(O(\sqrt{r}+\sqrt{s})\) time in the implementations shown here. If \(K(r)\) and \(K(s)\) denote the numbers of symmetry classes on the two axes, then the Burnside loop uses \(O(K(r)K(s))\) class pairs.
Each class profile has only one or two cycle lengths, so the product-cycle computation for one pair is \(O(1)\). Every distinct cycle count triggers one inclusion-exclusion evaluation in \(O(q)\), but \(q\le 40\) in Problem 651 and many class pairs share the same cycle count. Memory usage is \(O(K(r)+K(s)+U+q^2)\), where \(U\) is the number of distinct cached cycle counts. In practice the method is extremely small compared with the combinatorial size of the raw coloring space.
Footnotes and References
- Problem page: https://projecteuler.net/problem=651
- Burnside's lemma: Wikipedia — Burnside's lemma
- Inclusion-exclusion principle: Wikipedia — Inclusion-exclusion principle
- Euler's totient function: Wikipedia — Euler's totient function
- Dihedral group and cycle symmetries: Wikipedia — Dihedral group
- Stirling numbers of the second kind: Wikipedia — Stirling numbers of the second kind
Problem 651 source code
C++
#include <algorithm>
#include <array>
#include <cassert>
#include <cstdint>
#include <iostream>
#include <numeric>
#include <unordered_map>
#include <utility>
#include <vector>
namespace {
using u64 = std::uint64_t;
using u128 = __uint128_t;
constexpr u64 kMod = 1'000'000'007ULL;
u64 mod_mul(u64 a, u64 b) {
return static_cast<u64>((static_cast<u128>(a) * static_cast<u128>(b)) % kMod);
}
u64 mod_pow(u64 base, u64 exp) {
u64 result = 1;
base %= kMod;
while (exp > 0) {
if (exp & 1ULL) result = mod_mul(result, base);
base = mod_mul(base, base);
exp >>= 1ULL;
}
return result;
}
std::vector<std::pair<u64, int>> factorize(u64 n) {
std::vector<std::pair<u64, int>> factors;
u64 x = n;
for (u64 p = 2; p * p <= x; p += (p == 2 ? 1 : 2)) {
if (x % p != 0) continue;
int e = 0;
while (x % p == 0) {
x /= p;
++e;
}
factors.emplace_back(p, e);
}
if (x > 1) factors.emplace_back(x, 1);
return factors;
}
struct DivPhi {
u64 d;
u64 phi;
};
void gen_div_phi_rec(const std::vector<std::pair<u64, int>>& factors,
int idx,
u64 d,
u64 phi,
std::vector<DivPhi>& out) {
if (idx == static_cast<int>(factors.size())) {
out.push_back({d, phi});
return;
}
const u64 p = factors[idx].first;
const int emax = factors[idx].second;
gen_div_phi_rec(factors, idx + 1, d, phi, out);
u64 p_pow = 1;
for (int e = 1; e <= emax; ++e) {
p_pow *= p;
u64 phi_factor = (p - 1);
for (int i = 1; i < e; ++i) phi_factor *= p;
gen_div_phi_rec(factors, idx + 1, d * p_pow, phi * phi_factor, out);
}
}
std::vector<DivPhi> divisors_with_phi(u64 n) {
std::vector<DivPhi> out;
const auto factors = factorize(n);
gen_div_phi_rec(factors, 0, 1, 1, out);
return out;
}
struct CycleType {
u64 length;
u64 count;
};
struct ClassType {
u64 multiplicity;
std::vector<CycleType> cycles;
};
std::vector<ClassType> build_affine_classes(u64 n) {
std::vector<ClassType> classes;
if (n == 1) {
classes.push_back({1, {{1, 1}}});
return classes;
}
if (n == 2) {
classes.push_back({1, {{1, 2}}});
classes.push_back({1, {{2, 1}}});
return classes;
}
const auto div_phi = divisors_with_phi(n);
classes.reserve(div_phi.size() + 2);
for (const auto& row : div_phi) {
const u64 u = row.d;
const u64 phi_u = row.phi;
classes.push_back({phi_u, {{u, n / u}}});
}
if (n & 1ULL) {
classes.push_back({n, {{1, 1}, {2, (n - 1) / 2}}});
} else {
classes.push_back({n / 2, {{1, 2}, {2, (n - 2) / 2}}});
classes.push_back({n / 2, {{2, n / 2}}});
}
return classes;
}
u64 surjections_mod(u64 cycle_count, int colors, const std::array<std::array<u64, 41>, 41>& comb) {
u64 result = 0;
for (int j = 0; j <= colors; ++j) {
const u64 ways_pick = comb[colors][j];
const u64 ways_map = mod_pow(static_cast<u64>(colors - j), cycle_count);
const u64 term = mod_mul(ways_pick, ways_map);
if (j & 1) {
result = (result + kMod - term) % kMod;
} else {
result += term;
if (result >= kMod) result -= kMod;
}
}
return result;
}
u64 cycle_count_product(const std::vector<CycleType>& x, const std::vector<CycleType>& y) {
u128 total = 0;
for (const auto& cx : x) {
for (const auto& cy : y) {
const u64 g = std::gcd(cx.length, cy.length);
total += static_cast<u128>(cx.count) * static_cast<u128>(cy.count) * static_cast<u128>(g);
}
}
return static_cast<u64>(total);
}
u64 solve_case(int colors, u64 a, u64 b, const std::array<std::array<u64, 41>, 41>& comb) {
const auto classes_a = build_affine_classes(a);
const auto classes_b = build_affine_classes(b);
u64 group_a = 0;
for (const auto& c : classes_a) group_a += c.multiplicity;
u64 group_b = 0;
for (const auto& c : classes_b) group_b += c.multiplicity;
const u64 group_mod = mod_mul(group_a % kMod, group_b % kMod);
const u64 inv_group = mod_pow(group_mod, kMod - 2);
u64 burnside_sum = 0;
std::unordered_map<u64, u64> cache;
cache.reserve(classes_a.size() * classes_b.size() * 2);
for (const auto& ca : classes_a) {
for (const auto& cb : classes_b) {
const u64 c = cycle_count_product(ca.cycles, cb.cycles);
auto it = cache.find(c);
u64 onto = 0;
if (it == cache.end()) {
onto = surjections_mod(c, colors, comb);
cache.emplace(c, onto);
} else {
onto = it->second;
}
const u64 mult = mod_mul(ca.multiplicity % kMod, cb.multiplicity % kMod);
burnside_sum += mod_mul(mult, onto);
if (burnside_sum >= kMod) burnside_sum -= kMod;
}
}
return mod_mul(burnside_sum, inv_group);
}
std::array<std::array<u64, 41>, 41> build_comb() {
std::array<std::array<u64, 41>, 41> c{};
c[0][0] = 1;
for (int n = 1; n <= 40; ++n) {
c[n][0] = 1;
c[n][n] = 1;
for (int k = 1; k < n; ++k) {
c[n][k] = c[n - 1][k - 1] + c[n - 1][k];
}
}
return c;
}
u64 solve() {
const auto comb = build_comb();
assert(solve_case(2, 2, 3, comb) == 11);
assert(solve_case(3, 2, 3, comb) == 56);
assert(solve_case(2, 3, 4, comb) == 156);
assert(solve_case(8, 13, 21, comb) == 49718354);
assert(solve_case(13, 144, 233, comb) == 907081451);
std::vector<u64> fib(41, 0);
fib[1] = 1;
for (int i = 2; i <= 40; ++i) fib[i] = fib[i - 1] + fib[i - 2];
u64 ans = 0;
for (int i = 4; i <= 40; ++i) {
ans += solve_case(i, fib[i - 1], fib[i], comb);
ans %= kMod;
}
return ans;
}
} // namespace
int main() {
std::cout << solve() << "\n";
return 0;
}
Python
import math
MOD = 1000000007
def mod_pow(base, exp):
return pow(base, exp, MOD)
def factorize(n):
factors = []
x = n
p = 2
while p * p <= x:
if x % p == 0:
e = 0
while x % p == 0:
x //= p
e += 1
factors.append((p, e))
p += 1 if p == 2 else 2
if x > 1:
factors.append((x, 1))
return factors
def gen_div_phi_rec(factors, idx, d, phi, out):
if idx == len(factors):
out.append((d, phi))
return
p, emax = factors[idx]
gen_div_phi_rec(factors, idx + 1, d, phi, out)
p_pow = 1
for e in range(1, emax + 1):
p_pow *= p
phi_factor = p - 1
for i in range(1, e):
phi_factor *= p
gen_div_phi_rec(factors, idx + 1, d * p_pow, phi * phi_factor, out)
def divisors_with_phi(n):
out = []
factors = factorize(n)
gen_div_phi_rec(factors, 0, 1, 1, out)
return out
class CycleType:
def __init__(self, length, count):
self.length = length
self.count = count
class ClassType:
def __init__(self, multiplicity, cycles):
self.multiplicity = multiplicity
self.cycles = cycles
def build_affine_classes(n):
classes = []
if n == 1:
classes.append(ClassType(1, [CycleType(1, 1)]))
return classes
if n == 2:
classes.append(ClassType(1, [CycleType(1, 2)]))
classes.append(ClassType(1, [CycleType(2, 1)]))
return classes
div_phi = divisors_with_phi(n)
for u, phi_u in div_phi:
classes.append(ClassType(phi_u, [CycleType(u, n // u)]))
if n % 2 == 1:
classes.append(ClassType(n, [CycleType(1, 1), CycleType(2, (n - 1) // 2)]))
else:
classes.append(ClassType(n // 2, [CycleType(1, 2), CycleType(2, (n - 2) // 2)]))
classes.append(ClassType(n // 2, [CycleType(2, n // 2)]))
return classes
def surjections_mod(cycle_count, colors, comb):
result = 0
for j in range(colors + 1):
ways_pick = comb[colors][j]
ways_map = mod_pow(colors - j, cycle_count)
term = (ways_pick * ways_map) % MOD
if j % 2 == 1:
result = (result + MOD - term) % MOD
else:
result = (result + term) % MOD
return result
def cycle_count_product(x, y):
total = 0
for cx in x:
for cy in y:
g = math.gcd(cx.length, cy.length)
total += cx.count * cy.count * g
return total
def solve_case(colors, a, b, comb):
classes_a = build_affine_classes(a)
classes_b = build_affine_classes(b)
group_a = sum(c.multiplicity for c in classes_a)
group_b = sum(c.multiplicity for c in classes_b)
group_mod = ((group_a % MOD) * (group_b % MOD)) % MOD
inv_group = mod_pow(group_mod, MOD - 2)
burnside_sum = 0
cache = {}
for ca in classes_a:
for cb in classes_b:
c = cycle_count_product(ca.cycles, cb.cycles)
if c not in cache:
onto = surjections_mod(c, colors, comb)
cache[c] = onto
else:
onto = cache[c]
mult = ((ca.multiplicity % MOD) * (cb.multiplicity % MOD)) % MOD
burnside_sum = (burnside_sum + mult * onto) % MOD
return (burnside_sum * inv_group) % MOD
def build_comb():
c = [[0] * 41 for _ in range(41)]
c[0][0] = 1
for n in range(1, 41):
c[n][0] = 1
c[n][n] = 1
for k in range(1, n):
c[n][k] = (c[n - 1][k - 1] + c[n - 1][k]) % MOD
return c
def solve():
comb = build_comb()
fib = [0] * 41
fib[1] = 1
for i in range(2, 41):
fib[i] = fib[i - 1] + fib[i - 2]
ans = 0
for i in range(4, 41):
ans = (ans + solve_case(i, fib[i - 1], fib[i], comb)) % MOD
return str(ans)
if __name__ == '__main__':
print(solve())
Java
import java.nio.file.*;
import java.util.*;
import java.util.regex.*;
public class Euler651 {
private static final Pattern ANSWER_RE = Pattern.compile("answer\\s*:\\s*(.+)$", Pattern.CASE_INSENSITIVE);
private static final Pattern EQUAL_RE = Pattern.compile("=\\s*(.+)$");
private static String parseOutput(String stdout) {
String[] lines = stdout.split("\\R");
List<String> nonEmpty = new ArrayList<>();
for (String line : lines) {
String t = line.trim();
if (!t.isEmpty()) {
nonEmpty.add(t);
}
}
if (nonEmpty.isEmpty()) {
return "";
}
List<String> answers = new ArrayList<>();
List<String> equals = new ArrayList<>();
for (String line : nonEmpty) {
Matcher m1 = ANSWER_RE.matcher(line);
if (m1.find()) {
answers.add(m1.group(1).trim());
}
Matcher m2 = EQUAL_RE.matcher(line);
if (m2.find()) {
equals.add(m2.group(1).trim());
}
}
if (!answers.isEmpty()) {
return answers.get(answers.size() - 1);
}
if (!equals.isEmpty()) {
return equals.get(equals.size() - 1);
}
return nonEmpty.get(nonEmpty.size() - 1);
}
private static String pickCompiler() throws Exception {
for (String compiler : List.of("clang++", "g++")) {
Process probe = new ProcessBuilder("bash", "-lc", "command -v " + compiler)
.redirectErrorStream(true)
.start();
String out = new String(probe.getInputStream().readAllBytes());
int rc = probe.waitFor();
if (rc == 0 && !out.trim().isEmpty()) {
return compiler;
}
}
throw new RuntimeException("No C++ compiler found (clang++/g++).");
}
private static Path cppSource(Path root) {
return root.resolve("solutionsCpp").resolve("Euler651.cpp");
}
private static boolean shouldSkipCheckpoints(Path root) {
Path src = cppSource(root);
try {
String text = Files.readString(src);
return text.contains("--skip-checkpoints");
} catch (Exception ex) {
return false;
}
}
private static Path ensureBridgeBinary() throws Exception {
Path root = Paths.get(System.getProperty("user.dir"));
Path src = cppSource(root);
Path bin = root.resolve("solutionsCpp").resolve(".euler651_java_bridge");
boolean rebuild = Files.notExists(bin)
|| Files.getLastModifiedTime(src).compareTo(Files.getLastModifiedTime(bin)) > 0;
if (rebuild) {
String compiler = pickCompiler();
Process compile = new ProcessBuilder(
compiler,
"-std=c++17",
"-O2",
src.toString(),
"-o",
bin.toString())
.inheritIO()
.start();
if (compile.waitFor() != 0) {
throw new RuntimeException("Failed to compile Euler651 C++ bridge.");
}
}
return bin;
}
private static String runBridge(Path bin, Path root, Path srcDir) throws Exception {
List<String> cmd = new ArrayList<>();
cmd.add(bin.toString());
if (shouldSkipCheckpoints(root)) {
cmd.add("--skip-checkpoints");
}
Process first = new ProcessBuilder(cmd)
.directory(root.toFile())
.redirectErrorStream(true)
.start();
String out = new String(first.getInputStream().readAllBytes());
int rc = first.waitFor();
if (rc == 0) {
return out;
}
Process second = new ProcessBuilder(cmd)
.directory(srcDir.toFile())
.redirectErrorStream(true)
.start();
String out2 = new String(second.getInputStream().readAllBytes());
int rc2 = second.waitFor();
if (rc2 == 0) {
return out2;
}
throw new RuntimeException("Euler651 C++ bridge failed.\n" + out + "\n" + out2);
}
private static String solveViaCppBridge() throws Exception {
Path root = Paths.get(System.getProperty("user.dir"));
Path src = cppSource(root);
Path bin = ensureBridgeBinary();
String out = runBridge(bin, root, src.getParent());
String parsed = parseOutput(out);
if (parsed.isEmpty()) {
throw new RuntimeException("Euler651 C++ bridge produced empty output.");
}
return parsed;
}
public static void main(String[] args) throws Exception {
System.out.println(solveViaCppBridge());
}
}