Untitled
unknown
plain_text
a year ago
3.9 kB
12
Indexable
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
vector<int> primes = {2, 3, 5, 7, 11};
int modInv(int n, int p) {
// Return the modular inverse of n mod p.
//
// 0 ~= p = q*n + r hence r ~= -q*n hence 1/n ~= -q/r
int a = 1;
while (1 < n) {
// The answer is a*1/n
a *= -p/n, n = p%n;
}
return a;
}
int mod2Equations(int a, int ra, int p, int rp) {
// Return the smaller nonnegative solution n of the system of two
// modular equations (n ~= ra [mod a] and n ~= rp [mod p]), where
// p is a prime number and a is a number coprime with p.
// n ~= ra [mod a] is equivalent to n = qa*a + ra for some qa.
// Hence, n ~= rp [mod p] rewrites as qa*a ~= rp - ra [mod p].
// Since p is prime, this is equivalent to qa ~= (rp - ra)/a [mod
// p] where 1/a is the modular inverse of a.
int qa = ((rp - ra)%p + p)%p*modInv(a%p, p)%p;
return qa*a + ra;
}
int modSystem(const vector<int> &remainders) {
// Return the smaller nonnegative solution of the system of
// modular equations (n ~= remainders[i] [mod primes[i]] for each
// i).
int n = remainders[0];
int a = primes[0];
for (int i = 1; i < 5; i++) {
n = mod2Equations(a, n, primes[i], remainders[i]), a *= primes[i];
}
return n;
}
bool dfs(int i, vector<vector<int>> &remaindersABC,
const vector<vector<vector<int>>> &possibilities,
vector<int> &ans) {
if (i == 5) {
int a = modSystem(remaindersABC[0]);
int b = modSystem(remaindersABC[1]);
int c = modSystem(remaindersABC[2]);
if (0 < a && a < b && b < c && a*a + b*b == c*c && a + b + c == 1000) {
// cout << a*a << " + " << b*b << " == " << c*c << "\n";
ans = {a, b, c};
return true;
}
else {
// cout << a*a << " + " << b*b << " != " << c*c << "\n";
return false;
}
}
else {
int m = possibilities[i].size();
for (int j = 0; j < m; j++) {
// Try the possibility j for the remainders modulo the
// prime number indexed i
for (int x = 0; x < 3; x++) {
remaindersABC[x][i] = possibilities[i][j][x];
}
if (dfs(i + 1, remaindersABC, possibilities, ans))
return true;
}
return false;
}
}
int main() {
// We search the unique triplet of positive numbers a < b < c such
// that (1) a^2 + b^2 = c^2 and (2) a + b + c = 1000.
//
// Each number up to 1000 < 2*3*5*7*11 is uniquely defined by its
// remainders modulo the prime numbers up to 11 as a special case
// of the Chinese remainders theorem.
//
// We enumerate over each possible remainders for a, b and c
// compatible with equations (1) and (2), and to find the
// corresponding numbers actually satisfying these equations.
vector<vector<vector<int>>> possibilities(5);
// possibilities[i]: array with each possible triplets of values
// {ra, rb, rc} for the remainders of a, b and c mod primes[i],
// according to equations (1) and (2)
for (int i = 0; i < 5; i++) {
// compute possibilities[i]
for (int ra = 0; ra < primes[i]; ra++) {
for (int rb = 0; rb < primes[i]; rb++) {
// ra, rb <= 11 so ra + rb <= 1000
int rc = (1000 - ra - rb)%primes[i];
if ((ra*ra + rb*rb)%primes[i] == rc*rc%primes[i])
possibilities[i].push_back({ra, rb, rc});
}
}
}
vector<vector<int>> remaindersABC(3, vector<int>(5));
// stores the remainders of a, b and c selected during the dfs
vector<int> ans;
bool res = dfs(0, remaindersABC, possibilities, ans);
cout << "a = " << ans[0] << "\nb = " << ans[1] << "\nc = " << ans[2] << "\n";
cout << "a*b*c = " << ans[0]*ans[1]*ans[2] << "\n";
}
Editor is loading...
Leave a Comment