$\newcommand{\O}{\mathrm{O}}$
"有理数→連分数展開", "連分数展開→有理数" の変換および $2$ つの有理数 $p, q (p < q)$ が与えられたときに $p$ と $q$ の真に間に存在する有理数 $r$ で (分子) + (分母) が最も小さいものを返す(ここで有理数と言ったとき(非負の)有理数を指すこととする).
(関数)
rtocf$(val, res)$: 有理数 $val$ を 連分数展開形 $res$ に変換する(2種類ある).
cftor$(val)$: 連分数展開形 $val$ を有理数に変換し, それを返す.
find_rational$(val1, val2)$: $2$ つの有理数 $val1, val2 (val1 < val2)$ が与えられたときに $val1$ と $val2$ の真に間に存在する有理数で (分子) + (分母) が最も小さいものを返す.
このとき (分子) + (分母) が最小のものは一意に定まることに注意する.
時間計算量: 各操作 $\O (\log A)$ ($A = \max(分子, 分母)$ とする.)
template<typename T> class Rational { private: static Rational make(const T& x, const T& y){ Rational m; return m.num = x, m.den = y, m; } public: friend ostream& operator<<(ostream& os, const Rational& rn) { return (os << rn.num << " / " << rn.den); } Rational& operator=(T val){ return *this = Rational(val); } bool operator<(const Rational& val) const { return num*val.den < den*val.num; } bool operator<(const T val) const { return *this < Rational(val); } friend bool operator<(const T val1, const Rational& val2){ return Rational(val1) < val2; } bool operator>(const Rational& val) const { return val < *this; } bool operator>(const T val) const { return *this > Rational(val); } friend bool operator>(const T val1, const Rational& val2){ return Rational(val1) > val2; } bool operator<=(const Rational& val) const { return !(*this > val); } bool operator<=(const T val) const { return *this <= Rational(val); } friend bool operator<=(const T val1, const Rational& val2){ return Rational(val1) <= val2; } bool operator>=(const Rational& val) const { return !(*this < val); } bool operator>=(const T val) const { return *this >= Rational(val); } friend bool operator>=(const T val1, const Rational& val2){ return Rational(val1) >= val2; } bool operator==(const Rational& val) const { return num*val.den == den*val.num; } bool operator==(const T val) const { return *this == Rational(val); } friend bool operator==(const T val1, const Rational& val2){ return Rational(val1) == val2; } bool operator!=(const Rational& val) const { return !(*this == val); } bool operator!=(const T val) const { return *this != Rational(val); } friend bool operator!=(const T val1, const Rational& val2){ return Rational(val1) != val2; } explicit operator bool() const noexcept { return num; } bool operator!() const noexcept { return !static_cast<bool>(*this); } Rational operator+() const { return *this; } Rational operator-() const { return make(-num, den); } friend Rational abs(const Rational& val){ return make(abs(val.num), val.den); } Rational operator+(const Rational& val) const { return make(num*val.den+val.num*den, den*val.den); } Rational operator+(T val) const { return *this + Rational(val); } friend Rational operator+(T a, const Rational& b){ return b + a; } Rational& operator+=(const Rational& val){ return *this = *this + val; } Rational& operator+=(const T& val){ return *this = *this + val; } Rational& operator++(){ return *this += 1; } Rational operator++(int){ return make(num + den, den); } Rational operator-(const Rational& val) const { return make(num*val.den-val.num*den, den*val.den); } Rational operator-(T val) const { return *this - Rational(val); } friend Rational operator-(T a, const Rational& b){ return Rational(a) - b; } Rational& operator-=(const Rational& val){ return *this = *this - val; } Rational& operator-=(const T& val){ return *this = *this - val; } Rational& operator--(){ return *this -= 1; } Rational operator--(int){ return make(num - den, den); } Rational operator*(const Rational& val) const { return make(num*val.num, den*val.den); } Rational operator*(T val) const { return *this * Rational(val); } friend Rational operator*(T a, const Rational& b){ return b * a; } Rational& operator*=(const Rational& val){ return *this = *this * val;} Rational& operator*=(const T& val){ return *this = *this * val; } Rational operator/(const Rational& val) const { return make(num*val.den, den*val.num); } Rational operator/(T val) const { return *this / Rational(val); } friend Rational operator/(T a, const Rational& b){ return Rational(a) / b; } Rational& operator/=(const Rational& val){ return *this / val; } Rational& operator/=(const T& val){ return *this = *this / val; } T num, den; Rational(){} Rational(T num_) : num(num_), den(1){} Rational(T num_, T den_) : num(num_), den(den_){ if(den < 0) num = -num, den = -den; } }; template<typename T> bool is_valid(const Rational<T>& a, const Rational<T>& b, const Rational<T>& c) { return (a < b && b < c); } template<typename T> void rtocf(const Rational<T>& val, vector<vector<T> >& res) { if(res.empty()) res.push_back(vector<T>()); res[0].push_back(val.num / val.den); long long mod = val.num % val.den; if(mod == 0){ res.push_back(res[0]); if(res[0].back() == 1 && (int)res[0].size() > 1){ res[1].pop_back(), --res[1].back(); }else{ --res[0].back(), res[0].push_back(1); } return; }else{ rtocf(Rational<T>(val.den, val.num-res[0].back()*val.den) , res); } } template<typename T> Rational<T> cftor(vector<T> val) { T a = 1, b = 0; while(!val.empty()){ swap(a, b); a += val.back()*b; val.pop_back(); } return Rational<T>(a, b); } template<typename T> Rational<T> find_rational(const Rational<T> val1, const Rational<T> val2) { vector<vector<T> > l, r; rtocf(val1, l), rtocf(val2, r); vector<T> res; for(vector<T>& lvec : l){ for(vector<T>& rvec : r){ vector<T> nw; int i = 0, mn_size = min((int)lvec.size(), (int)rvec.size()); for(i = 0; i < mn_size; ++i){ if(lvec[i] != rvec[i]){ nw.push_back(min(lvec[i], rvec[i]) + 1); break; }else{ nw.push_back(lvec[i]); } } if(i == mn_size){ if((int)lvec.size() > mn_size){ nw.push_back(lvec[mn_size]+1); }else{ nw.push_back(rvec[mn_size]+1); } } Rational<T> cand = cftor(nw); if(is_valid(val1, cand, val2)) return cand; } } return Rational<T>(); }
GCJ : New Elements: Part 2