kyopro-lib

This documentation is automatically generated by online-judge-tools/verification-helper

View on GitHub

:heavy_check_mark: test/aoj/1300/main.test.cpp

Depends on

Code

#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;
}
Back to top page