diff --git a/combinatorial_opt/linear_sum_assignment.md b/combinatorial_opt/linear_sum_assignment.md index 19721510..6e8ec759 100644 --- a/combinatorial_opt/linear_sum_assignment.md +++ b/combinatorial_opt/linear_sum_assignment.md @@ -60,6 +60,7 @@ for (int t = 0; t < k; ++t) { ## 問題例 - [Library Checker: Assignment Problem](https://judge.yosupo.jp/problem/assignment) +- [No.3306 Life is Easy? - yukicoder](https://yukicoder.me/problems/no/3306) ## 文献・リンク集 diff --git a/combinatorial_opt/test/linear_sum_assignment.yuki3306.test.cpp b/combinatorial_opt/test/linear_sum_assignment.yuki3306.test.cpp new file mode 100644 index 00000000..f15dfc87 --- /dev/null +++ b/combinatorial_opt/test/linear_sum_assignment.yuki3306.test.cpp @@ -0,0 +1,31 @@ +#define PROBLEM "https://yukicoder.me/problems/no/3306" + +#include "../linear_sum_assignment.hpp" + +#include +#include +using namespace std; + +int main() { + cin.tie(nullptr), ios::sync_with_stdio(false); + + int N, M; + cin >> N >> M; + vector A(N, vector(M)); + for (auto &v : A) { + for (auto &x : v) cin >> x; + } + + const int K = N / 2; + vector mat(K, vector(K)); + for (int i = 0; i < K; ++i) { + for (int j = 0; j < K; ++j) { + int best = 0; + for (int k = 0; k < M; ++k) best = max(best, A.at(N - 1 - j).at(k) - A.at(i).at(k)); + mat.at(i).at(j) = -best; + } + } + + auto res = linear_sum_assignment::solve(K, K, mat); + cout << -res.opt << '\n'; +} diff --git a/utilities/floor_sum.hpp b/utilities/floor_sum.hpp index ada8ab05..c37ef0c5 100644 --- a/utilities/floor_sum.hpp +++ b/utilities/floor_sum.hpp @@ -6,6 +6,7 @@ // 1 <= m < 2e32 (if Int is long long) // 0 <= a, b < m // Complexity: O(lg(m)) +// (Int, Unsigned) = (long long, unsigned long long), (__int128_t, __uint128_t) template Int floor_sum(Int n, Int m, Int a, Int b) { static_assert(-Int(1) < 0, "Int must be signed"); static_assert(-Unsigned(1) > 0, "Unsigned must be unsigned"); diff --git a/utilities/test/floor_sum.int128.yuki3307.test.cpp b/utilities/test/floor_sum.int128.yuki3307.test.cpp new file mode 100644 index 00000000..37832515 --- /dev/null +++ b/utilities/test/floor_sum.int128.yuki3307.test.cpp @@ -0,0 +1,32 @@ +#define PROBLEM "https://yukicoder.me/problems/no/3307" +#include "../floor_sum.hpp" +#include +using namespace std; + +int main() { + cin.tie(nullptr), ios::sync_with_stdio(false); + + long long A, B, C, D; + cin >> A >> B >> C >> D; + + if (A * D == B * C) { + cout << "-1\n"; + return 0; + } + + if (A * D > C * B) swap(A, C), swap(B, D); + + // round(i * A / B) = floor(iA/B + 1/2) = floor((2iA + B)/2B) + + // A/B < C/D + // i(A/B) + 1 <= i(C/D) + // i(C/D - A/B) >= 1 + // i(BC - AD) >= BD + + const auto det = B * C - A * D; + const auto ub = (B * D + det - 1) / det; + + const auto ret = floor_sum<__int128_t, __uint128_t>(ub, D * 2, C * 2, D) - + floor_sum<__int128_t, __uint128_t>(ub, B * 2, A * 2, B); + cout << (long long)(ub - ret - 1) << '\n'; +}