#define PROBLEM "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1300" #include <iostream> #include <map> #include <string> #include <vector> #include "Mylib/IO/join.cpp" #include "Mylib/LinearAlgebra/gaussian_elimination.cpp" #include "Mylib/Number/Rational/rational.cpp" #include "Mylib/Parser/parser.cpp" #include "Mylib/String/split.cpp" namespace hl = haar_lib; using result = std::map<std::string, int>; struct parser : hl::parser { parser(const std::string &s) : hl::parser(s) {} std::string atom() { std::string ret; ret += get_char(); if (lower()) ret += get_char(); return ret; } result factor() { result ret; if (check_and_ignore('(')) { ret = expression(); ignore(')'); } else { ret[atom()] = 1; } if (digit()) { int n = get_number<int>(); for (auto &kv : ret) { kv.second *= n; } } return ret; } result expression() { result ret = factor(); while (1) { if (digit() or alpha() or check('(')) { result temp = factor(); for (auto &[k, v] : temp) { ret[k] += v; } } else { break; } } return ret; } result run() { return expression(); } }; int main() { std::cin.tie(0); std::ios::sync_with_stdio(false); std::string s; while (std::cin >> s) { if (s == ".") break; s.pop_back(); // pop period auto a = hl::split(s, "->"); auto b = hl::split(a[0], "+"); auto c = hl::split(a[1], "+"); std::map<std::string, int> atoms; std::vector<result> ress; for (auto &x : b) { auto r = parser(x).run(); for (auto &kv : r) { atoms[kv.first] = 0; } ress.push_back(r); } for (auto &x : c) { auto r = parser(x).run(); for (auto &kv : r) { atoms[kv.first] = 0; kv.second = -kv.second; } ress.push_back(r); } { int i = 0; for (auto &kv : atoms) { kv.second = i++; } } std::vector<std::vector<hl::rational>> mat(atoms.size(), std::vector<hl::rational>(ress.size())); for (int i = 0; i < (int) ress.size(); ++i) { for (auto &[k, v] : ress[i]) { mat[atoms[k]][i] = v; } } hl::gaussian_elimination(mat); const int n = ress.size(); std::vector<hl::rational> ans(n); ans[n - 1] = 1; for (int i = (int) atoms.size(); --i >= 0;) { if (mat[i].back() == 0) continue; int k = 0; hl::rational coef; hl::rational cons; for (int j = 0; j < n; ++j) { if (ans[j] == 0) { k = j; coef = mat[i][j]; } else { cons += mat[i][j] * ans[j]; } } ans[k] = -cons / coef; } int64_t l = 1; for (int i = 0; i < n; ++i) l = std::lcm(l, ans[i].denominator()); for (int i = 0; i < n; ++i) ans[i] *= l; std::cout << hl::join(ans.begin(), ans.end()) << "\n"; } return 0; }
#line 1 "test/aoj/1300/main.test.cpp" #define PROBLEM "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1300" #include <iostream> #include <map> #include <string> #include <vector> #line 3 "Mylib/IO/join.cpp" #include <sstream> #line 5 "Mylib/IO/join.cpp" namespace haar_lib { template <typename Iter> std::string join(Iter first, Iter last, std::string delim = " ") { std::stringstream s; for (auto it = first; it != last; ++it) { if (it != first) s << delim; s << *it; } return s.str(); } } // namespace haar_lib #line 2 "Mylib/LinearAlgebra/gaussian_elimination.cpp" #include <utility> #line 4 "Mylib/LinearAlgebra/gaussian_elimination.cpp" namespace haar_lib { template <typename T> int gaussian_elimination(std::vector<std::vector<T>> &a) { const int h = a.size(); const int w = a[0].size(); int rank = 0; for (int j = 0; j < w; ++j) { int pivot = -1; for (int i = rank; i < h; ++i) { if (a[i][j] != 0) { pivot = i; break; } } if (pivot == -1) continue; std::swap(a[pivot], a[rank]); auto d = a[rank][j]; for (int k = 0; k < w; ++k) a[rank][k] /= d; for (int i = 0; i < h; ++i) { if (i == rank or a[i][j] == 0) continue; auto d = a[i][j]; for (int k = 0; k < w; ++k) { a[i][k] -= a[rank][k] * d; } } ++rank; } return rank; } } // namespace haar_lib #line 2 "Mylib/Number/Rational/rational.cpp" #include <cmath> #line 4 "Mylib/Number/Rational/rational.cpp" #include <numeric> namespace haar_lib { class rational { int64_t nume_, deno_; public: rational() : nume_(0), deno_(1) {} rational(int64_t nume) : nume_(nume), deno_(1) {} rational(int64_t nume, int64_t deno) { const int64_t g = std::gcd(nume, deno); nume_ = nume / g; deno_ = deno / g; if (deno_ < 0) { nume_ = -nume_; deno_ = -deno_; } } int64_t numerator() const { return nume_; } int64_t denominator() const { return deno_; } auto operator+(const rational &b) { int64_t l = std::lcm((*this).deno_, b.deno_); return rational(l / (*this).deno_ * (*this).nume_ + l / b.deno_ * b.nume_, l); } auto operator-(const rational &b) { int64_t l = std::lcm((*this).deno_, b.deno_); return rational(l / (*this).deno_ * (*this).nume_ - l / b.deno_ * b.nume_, l); } auto operator*(const rational &b) { return rational((*this).nume_ * b.nume_, (*this).deno_ * b.deno_); } auto operator/(const rational &b) { return rational((*this).nume_ * b.deno_, (*this).deno_ * b.nume_); } auto &operator+=(const rational &a) { *this = *this + a; return *this; } auto &operator-=(const rational &a) { *this = *this - a; return *this; } auto &operator*=(const rational &a) { *this = *this * a; return *this; } auto &operator/=(const rational &a) { *this = *this / a; return *this; } explicit operator double() const { return (double) nume_ / deno_; } explicit operator long double() const { return (long double) nume_ / deno_; } auto operator-() { return rational(-nume_, deno_); } friend std::ostream &operator<<(std::ostream &os, const rational &r) { if (r.deno_ == 1) os << r.nume_; else os << r.nume_ << "/" << r.deno_; return os; } friend bool operator==(const rational &a, const rational &b) { return a.nume_ == b.nume_ and a.deno_ == b.deno_; } friend bool operator!=(const rational &a, const rational &b) { return !(a == b); } friend bool operator<(const rational &a, const rational &b) { return a.nume_ * b.deno_ < b.nume_ * a.deno_; } friend bool operator<=(const rational &a, const rational &b) { return a.nume_ * b.deno_ <= b.nume_ * a.deno_; } friend bool operator>(const rational &a, const rational &b) { return !(a <= b); } friend bool operator>=(const rational &a, const rational &b) { return !(a < b); } friend auto abs(const rational &a) { return rational(std::abs(a.nume_), std::abs(a.deno_)); } }; } // namespace haar_lib #line 2 "Mylib/Parser/parser.cpp" #include <cassert> #line 4 "Mylib/Parser/parser.cpp" namespace haar_lib { struct parser { using state = std::string::const_iterator; state cur, first, last; parser() {} parser(const std::string &s) : cur(s.cbegin()), first(s.cbegin()), last(s.cend()) {} char peek() const { return *cur; } bool check(char c) const { return *cur == c; } bool check(const std::string &s) const { state temp = cur; for (auto c : s) { if (c != *temp) return false; ++temp; } return true; } void ignore(char c) { assert(*cur == c); ++cur; } void ignore() { ++cur; } void ignore(const std::string &s) { for (auto c : s) { assert(*cur == c); ++cur; } } template <class Checker> void ignore_if(const Checker &f) { assert(f(*cur)); ++cur; } bool check_and_ignore(char c) { if (*cur != c) return false; ++cur; return true; } bool end() const { return cur == last; } bool digit() const { return isdigit(*cur); } bool alpha() const { return isalpha(*cur); } bool lower() const { return islower(*cur); } bool upper() const { return isupper(*cur); } char get_char() { return *(cur++); } int get_digit() { return (int) (*(cur++) - '0'); } template <typename Checker> auto get_string(const Checker &f) { std::string ret; while (f(peek())) { ret += peek(); ignore(); } return ret; } auto get_string_alpha() { std::string ret; while (isalpha(*cur)) { ret += *cur; ++cur; } return ret; } auto get_string_alnum() { std::string ret; while (isalnum(*cur)) { ret += *cur; ++cur; } return ret; } template <typename T> T get_number() { T ret = get_digit(); while (digit()) { (ret *= 10) += (T)(get_digit()); } return ret; } }; } // namespace haar_lib #line 4 "Mylib/String/split.cpp" namespace haar_lib { auto split(const std::string &s, const std::string &delim) { std::vector<std::string> ret; size_t i = 0; while (1) { size_t j = s.find(delim, i); if (j == std::string::npos) break; ret.push_back(s.substr(i, j - i)); i = j + delim.size(); } ret.push_back(s.substr(i, s.size() - i)); return ret; } } // namespace haar_lib #line 12 "test/aoj/1300/main.test.cpp" namespace hl = haar_lib; using result = std::map<std::string, int>; struct parser : hl::parser { parser(const std::string &s) : hl::parser(s) {} std::string atom() { std::string ret; ret += get_char(); if (lower()) ret += get_char(); return ret; } result factor() { result ret; if (check_and_ignore('(')) { ret = expression(); ignore(')'); } else { ret[atom()] = 1; } if (digit()) { int n = get_number<int>(); for (auto &kv : ret) { kv.second *= n; } } return ret; } result expression() { result ret = factor(); while (1) { if (digit() or alpha() or check('(')) { result temp = factor(); for (auto &[k, v] : temp) { ret[k] += v; } } else { break; } } return ret; } result run() { return expression(); } }; int main() { std::cin.tie(0); std::ios::sync_with_stdio(false); std::string s; while (std::cin >> s) { if (s == ".") break; s.pop_back(); // pop period auto a = hl::split(s, "->"); auto b = hl::split(a[0], "+"); auto c = hl::split(a[1], "+"); std::map<std::string, int> atoms; std::vector<result> ress; for (auto &x : b) { auto r = parser(x).run(); for (auto &kv : r) { atoms[kv.first] = 0; } ress.push_back(r); } for (auto &x : c) { auto r = parser(x).run(); for (auto &kv : r) { atoms[kv.first] = 0; kv.second = -kv.second; } ress.push_back(r); } { int i = 0; for (auto &kv : atoms) { kv.second = i++; } } std::vector<std::vector<hl::rational>> mat(atoms.size(), std::vector<hl::rational>(ress.size())); for (int i = 0; i < (int) ress.size(); ++i) { for (auto &[k, v] : ress[i]) { mat[atoms[k]][i] = v; } } hl::gaussian_elimination(mat); const int n = ress.size(); std::vector<hl::rational> ans(n); ans[n - 1] = 1; for (int i = (int) atoms.size(); --i >= 0;) { if (mat[i].back() == 0) continue; int k = 0; hl::rational coef; hl::rational cons; for (int j = 0; j < n; ++j) { if (ans[j] == 0) { k = j; coef = mat[i][j]; } else { cons += mat[i][j] * ans[j]; } } ans[k] = -cons / coef; } int64_t l = 1; for (int i = 0; i < n; ++i) l = std::lcm(l, ans[i].denominator()); for (int i = 0; i < n; ++i) ans[i] *= l; std::cout << hl::join(ans.begin(), ans.end()) << "\n"; } return 0; }