-
Notifications
You must be signed in to change notification settings - Fork 1
/
106.cc
134 lines (108 loc) · 3.19 KB
/
106.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <algorithm>
#include <bitset>
#include <iostream>
enum { MAX_UPPER_LIMIT = 1000000, };
// Generate coprime pairs (base, coprime).
class CoprimeSequence {
public:
explicit CoprimeSequence(int base);
bool Next();
int base() const;
int coprime() const;
private:
int base_;
int coprime_;
};
class PrimitivePythagoreanTriples {
public:
explicit PrimitivePythagoreanTriples(int upper_limit);
bool Next();
int a() const;
int b() const;
int c() const;
private:
bool NextBase();
CoprimeSequence sequence_;
int upper_limit_, a_, b_, c_;
};
bool IsOddNumber(int n) { return n & 1; }
bool IsEvenNumber(int n) { return !IsOddNumber(n); }
void MinMax(int* p, int* q) {
if (*p > *q) {
std::swap(*p, *q);
}
}
int ComputeGcd(int a, int b);
int main() {
std::bitset<MAX_UPPER_LIMIT + 1> is_part_of_any_pythagorean_triple;
for (int upper_limit = 0; std::cin >> upper_limit;) {
int num_primitive_pythagorean_triples = 0;
is_part_of_any_pythagorean_triple.reset();
PrimitivePythagoreanTriples ppt(upper_limit);
while (ppt.Next()) {
num_primitive_pythagorean_triples++;
int a = ppt.a(), b = ppt.b(), c = ppt.c();
for (int k = 1; k * c <= upper_limit; k++) {
is_part_of_any_pythagorean_triple.set(k * a);
is_part_of_any_pythagorean_triple.set(k * b);
is_part_of_any_pythagorean_triple.set(k * c);
}
}
std::cout << num_primitive_pythagorean_triples << ' '
<< upper_limit - is_part_of_any_pythagorean_triple.count()
<< std::endl;
}
return 0;
}
CoprimeSequence::CoprimeSequence(int base)
: base_(base), coprime_(IsEvenNumber(base) ? -1 : 0) {}
bool CoprimeSequence::Next() {
do {
coprime_ += 2;
} while (ComputeGcd(base_, coprime_) > 1);
return true;
}
int CoprimeSequence::base() const { return base_; }
int CoprimeSequence::coprime() const { return coprime_; }
PrimitivePythagoreanTriples::PrimitivePythagoreanTriples(int upper_limit)
: sequence_(2), upper_limit_(upper_limit), a_(0), b_(0), c_(0) {}
bool PrimitivePythagoreanTriples::Next() {
// The least value of 'c' that Euclid's formula can generate.
// If it is still greater than upper_limit, we are done.
if (sequence_.base() * sequence_.base() + 1 * 1 > upper_limit_) {
return false;
}
// Move to the next coprime pair.
if (!sequence_.Next()) {
return NextBase();
}
// Use Euclid's formula for generating (primitive) Pythagorean triples
// such that a < b < c <= upper_limit.
int n = sequence_.base(), m = sequence_.coprime();
MinMax(&n, &m);
int a = m * m - n * n, b = 2 * m * n, c = m * m + n * n;
MinMax(&a, &b);
if (c > upper_limit_) {
return NextBase();
}
a_ = a;
b_ = b;
c_ = c;
return true;
}
// Move to the next base value.
bool PrimitivePythagoreanTriples::NextBase() {
sequence_ = CoprimeSequence(sequence_.base() + 2);
return Next();
}
int PrimitivePythagoreanTriples::a() const { return a_; }
int PrimitivePythagoreanTriples::b() const { return b_; }
int PrimitivePythagoreanTriples::c() const { return c_; }
// Use Euclidean algorithm for the greatest common divisior.
int ComputeGcd(int a, int b) {
while (b) {
a %= b;
std::swap(a, b);
}
return a;
}