Skip to content

Commit

Permalink
Merge pull request #1028 from maspypy/master
Browse files Browse the repository at this point in the history
[問題追加] gcd of gaussian integers
  • Loading branch information
maspypy authored Nov 21, 2023
2 parents 24cb0b1 + 287258a commit 7bd4192
Show file tree
Hide file tree
Showing 13 changed files with 439 additions and 0 deletions.
29 changes: 29 additions & 0 deletions math/gcd_of_gaussian_integers/checker.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <vector>
#include <utility>
#include <stdint.h>
#include <inttypes.h>
#include "testlib.h"

using namespace std;

int main(int argc, char* argv[]) {
setName("compare sequences of tokens");
registerTestlibCmd(argc, argv);

int T = inf.readInt();

for (int t = 0; t < T; ++t) {
int ouf_a = ouf.readInt();
int ouf_b = ouf.readInt();
int ans_a = ans.readInt();
int ans_b = ans.readInt();
bool ok = 0;
for (int i = 0; i < 4; ++i) {
tie(ans_a, ans_b) = make_pair(ans_b, -ans_a);
if (ouf_a == ans_a && ouf_b == ans_b) ok = 1;
}
if (!ok) { quitf(_wa, "wa, gcd is not correct"); }
}
quitf(_ok, "OK");
return 0;
}
69 changes: 69 additions & 0 deletions math/gcd_of_gaussian_integers/gaussian.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include <tuple>

template <typename T, typename U>
T floor(T x, U y) {
return (x > 0 ? x / y : (x - y + 1) / y);
}

template <typename T>
struct Gaussian_Integer {
T x, y;
using G = Gaussian_Integer;

Gaussian_Integer(T x = 0, T y = 0) : x(x), y(y) {}
Gaussian_Integer(pair<T, T> p) : x(p.fi), y(p.se) {}

T norm() const { return x * x + y * y; }
G conjugate() const { return G(x, -y); }

G &operator+=(const G &g) {
x += g.x, y += g.y;
return *this;
}
G &operator-=(const G &g) {
x -= g.x, y -= g.y;
return *this;
}
G &operator*=(const G &g) {
tie(x, y) = make_pair(x * g.x - y * g.y, x * g.y + y * g.x);
return *this;
}
G &operator/=(const G &g) {
*this *= g.conjugate();
T n = g.norm();
x = floor(x + n / 2, n);
y = floor(y + n / 2, n);
return *this;
}
G &operator%=(const G &g) {
auto q = G(*this) / g;
q *= g;
(*this) -= q;
return *this;
}
G operator-() { return G(-x, -y); }
G operator+(const G &g) { return G(*this) += g; }
G operator-(const G &g) { return G(*this) -= g; }
G operator*(const G &g) { return G(*this) *= g; }
G operator/(const G &g) { return G(*this) /= g; }
G operator%(const G &g) { return G(*this) %= g; }
bool operator==(const G &g) { return (x == g.x && y == g.y); }

static G gcd(G a, G b) {
while (b.x != 0 || b.y != 0) {
a %= b;
swap(a, b);
}
return a;
}

// (g,x,y) s.t ax+by=g
static tuple<G, G, G> extgcd(G a, G b) {
if (b.x != 0 || b.y != 0) {
G q = a / b;
auto [g, x, y] = extgcd(b, a - q * b);
return {g, y, x - q * y};
}
return {a, G{1, 0}, G{0, 0}};
}
};
9 changes: 9 additions & 0 deletions math/gcd_of_gaussian_integers/gen/example_00.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
8
8 0 6 0
0 0 0 0
0 0 4 8
4 0 6 2
1 2 3 4
1 -2 3 4
1 -3 5 -7
-344235 225420 -33882 162741
30 changes: 30 additions & 0 deletions math/gcd_of_gaussian_integers/gen/fibonacci_like.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include <iostream>
#include <vector>
#include <tuple>

#include "../params.h"
#include "random.h"

using namespace std;
using ll = long long;

int main(int, char* argv[]) {
long long seed = atoll(argv[1]);
auto gen = Random(seed);

int T = T_MAX;
printf("%d\n", T);
for (int t = 0; t < T; ++t) {
ll a = 1, b = 0, c = 0, d = 0;
while (1) {
int k = gen.uniform<int>(0, 3);
for (int i = 0; i < k; ++i) { tie(a, b) = make_pair(b, -a); }
ll aa = c + a, bb = d + b, cc = a, dd = b;
if (min<ll>({aa, bb, cc, dd}) < MIN) break;
if (max<ll>({aa, bb, cc, dd}) > MAX) break;
a = aa, b = bb, c = cc, d = dd;
}
printf("%lld %lld %lld %lld\n", a, b, c, d);
}
return 0;
}
38 changes: 38 additions & 0 deletions math/gcd_of_gaussian_integers/gen/large_gcd.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include <iostream>
#include <vector>
#include <tuple>

#include "../params.h"
#include "random.h"

using namespace std;
using ll = long long;

#include "../gaussian.hpp"

using G = Gaussian_Integer<ll>;

int main(int, char* argv[]) {
long long seed = atoll(argv[1]);
auto gen = Random(seed);

ll LIM1 = 1000;
ll LIM2 = 1000000 / 2;

auto gen_gauss = [&](ll LIM) -> G {
ll x = gen.uniform<int>(-LIM, LIM);
ll y = gen.uniform<int>(-LIM, LIM);
return G{x, y};
};

int T = T_MAX;
printf("%d\n", T);
for (int t = 0; t < T; ++t) {
G g = gen_gauss(LIM2);
G a = gen_gauss(LIM1);
G b = gen_gauss(LIM1);
a *= g, b *= g;
printf("%lld %lld %lld %lld\n", a.x, a.y, b.x, b.y);
}
return 0;
}
24 changes: 24 additions & 0 deletions math/gcd_of_gaussian_integers/gen/random.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include <iostream>
#include <vector>
#include <tuple>

#include "../params.h"
#include "random.h"

using namespace std;

int main(int, char* argv[]) {
long long seed = atoll(argv[1]);
auto gen = Random(seed);

int T = T_MAX;
printf("%d\n", T);
for (int t = 0; t < T; ++t) {
int a = gen.uniform<int>(MIN, MAX);
int b = gen.uniform<int>(MIN, MAX);
int c = gen.uniform<int>(MIN, MAX);
int d = gen.uniform<int>(MIN, MAX);
printf("%d %d %d %d\n", a, b, c, d);
}
return 0;
}
32 changes: 32 additions & 0 deletions math/gcd_of_gaussian_integers/gen/small.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include <iostream>
#include <vector>
#include <tuple>

#include "../params.h"
#include "random.h"

using namespace std;

int main(int, char* argv[]) {
long long seed = atoll(argv[1]);
// auto gen = Random(seed); つかわない

const int LIM = 10;
vector<tuple<int, int, int, int>> problems;
for (int a = -LIM; a <= LIM; ++a) {
for (int b = -LIM; b <= LIM; ++b) {
for (int c = -LIM; c <= LIM; ++c) {
for (int d = -LIM; d <= LIM; ++d) {
if ((a + b + c + d + seed) % 2 == 0)
problems.emplace_back(a, b, c, d);
}
}
}
}

int t = problems.size();
assert(1 <= t && t <= T_MAX);
printf("%d\n", t);
for (auto& [a, b, c, d]: problems) { printf("%d %d %d %d\n", a, b, c, d); }
return 0;
}
26 changes: 26 additions & 0 deletions math/gcd_of_gaussian_integers/hash.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"example_00.in": "7dc4086ba8bec80ef0442494f94ecc4a3c75c95a254541287dc5cf510505e798",
"example_00.out": "92d60e96fca7f75cecea6765a1f5c6ef19ad8dbdcf8bd143bc68e532d136dde3",
"fibonacci_like_00.in": "ef21064f421a0b2a0315a720191616108a9e0ae88c6497f9dd731236ace1c772",
"fibonacci_like_00.out": "902c656dda476a0a456e7dd4caf007959b880058822049d404db3d8c6ab5d154",
"fibonacci_like_01.in": "c59c734522884d8cf794590b4ed3e3242d0cb6a0eaab2ad5ef106fc0a9d46cf2",
"fibonacci_like_01.out": "628b2d4bf31bd31c1ef8c7742d82d3605f2e28986ed2760e7f5c5e1277f8245b",
"large_gcd_00.in": "d9478f45c4f0190fc3cd3542eb6b1532511435940b5f145568479ab489a98085",
"large_gcd_00.out": "98db471072ba552e365fd63092889aa3db929b72071eabd6a903e5149ad657f7",
"large_gcd_01.in": "14ac6874495297c0018908bdedf7091f99e86321959d7e3bc31930e2b36d9fb8",
"large_gcd_01.out": "2d6dcdbfe2b7ed410e86d8d5bf3938db4dc85bda29ac9f9b2587233b71093b59",
"random_00.in": "6e05b9b9b6b78ab540355def3a15b5b66e46d4eac200f862b76b978e5ca13120",
"random_00.out": "e20fac6eb4c1896334f2b27b4872e3d4ae54160eda5f43b4820d0b0b5d657ccb",
"random_01.in": "dfc10c33c94add6e5634143aecd6e6bf9af5e75980d8d4241a46f2ca005e3415",
"random_01.out": "0d529841ac84c6f6ccebd368f51e31153ebdbe7c5508220f47d309e94744a5ac",
"random_02.in": "a041c3e17d097ebe215e9fd21e92904780812384aafd862f358251b656aa021b",
"random_02.out": "8435c8d791ac6ac2c119d794acecbb744b0fcb96dd6d230f5af352d3fd083099",
"random_03.in": "28eb47c73ecd35f46a5f9fb4b93d225fba69e0f17950eb13db5c6f716abcf0d1",
"random_03.out": "e0f22148a4831745357cded508e63b54883166e52ae5dc73c39fe30a9e5890ad",
"random_04.in": "b6077663099db878634f78b06e4ac5e113057e4e2ed4b8292bc6c2f868952f86",
"random_04.out": "902772158b1abb1aaee812016737848b4f932eb9b5a98f99c534f21f343e5444",
"small_00.in": "3cbe5b6a235266af934850e3d27399a6e9ee4785dbe017f9a8be49bb72d4a52d",
"small_00.out": "62f870f657880fbffa49257dc28ff258fa553744cc6fed47a05ad3463d7af4da",
"small_01.in": "fa819ca05c040e2e8861bb418dfdfa2af2846b5d6d548daf57e03a7a7723b66b",
"small_01.out": "4b1063c4c397b40d8a6733bfd2a232ea128b54605059285c7bc34733711e5b5e"
}
32 changes: 32 additions & 0 deletions math/gcd_of_gaussian_integers/info.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
title = 'Gcd of Gaussian Integers'
timelimit = 5.0
forum = "https://github.com/yosupo06/library-checker-problems/issues/958"

[[tests]]
name = "example.in"
number = 1

[[tests]]
name = "small.cpp"
number = 2

[[tests]]
name = "random.cpp"
number = 5

[[tests]]
name = "fibonacci_like.cpp"
number = 2

[[tests]]
name = "large_gcd.cpp"
number = 2

[[solutions]]
name = "random_correct.cpp"
wrong = false

[params]
T_MAX = 100000
MIN = -1000000000
MAX = 1000000000
29 changes: 29 additions & 0 deletions math/gcd_of_gaussian_integers/sol/correct.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <cstdio>
#include <vector>
#include <cassert>

using namespace std;
using ll = long long;

#include "../gaussian.hpp"

using G = Gaussian_Integer<ll>;

int main() {
int T;
scanf("%d", &T);

for (int t = 0; t < T; ++t) {
ll a1, b1, a2, b2;
scanf("%lld %lld %lld %lld", &a1, &b1, &a2, &b2);
G a(a1, b1);
G b(a2, b2);
auto [g, x, y] = G::extgcd(a, b);
assert(a * x + b * y == g);
assert((g == G{0, 0} && a == G{0, 0}) || (a % g == 0));
assert((g == G{0, 0} && b == G{0, 0}) || (b % g == 0));
printf("%lld %lld\n", g.x, g.y);
}

return 0;
}
32 changes: 32 additions & 0 deletions math/gcd_of_gaussian_integers/sol/random_correct.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include <cstdio>
#include <vector>
#include <cassert>

using namespace std;
using ll = long long;

#include "../gaussian.hpp"

using G = Gaussian_Integer<ll>;

int main() {
int T;
scanf("%d", &T);

G I{0, 1};

for (int t = 0; t < T; ++t) {
ll a1, b1, a2, b2;
scanf("%lld %lld %lld %lld", &a1, &b1, &a2, &b2);
G a(a1, b1);
G b(a2, b2);
auto [g, x, y] = G::extgcd(a, b);
assert(a * x + b * y == g);
assert((g == G{0, 0} && a == G{0, 0}) || (a % g == 0));
assert((g == G{0, 0} && b == G{0, 0}) || (b % g == 0));
for (int i = 0; i < t % 4; ++i) { g *= I; }
printf("%lld %lld\n", g.x, g.y);
}

return 0;
}
Loading

0 comments on commit 7bd4192

Please sign in to comment.