結果
| 問題 | No.1936 Rational Approximation |
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2026-01-08 05:01:28 |
| 言語 | C++23 (gcc 15.2.0 + boost 1.89.0) |
| 結果 |
AC
|
| 実行時間 | 2 ms / 2,000 ms |
| コード長 | 16,647 bytes |
| 記録 | |
| コンパイル時間 | 2,494 ms |
| コンパイル使用メモリ | 213,760 KB |
| 実行使用メモリ | 7,852 KB |
| 最終ジャッジ日時 | 2026-01-08 05:01:32 |
| 合計ジャッジ時間 | 2,887 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 1 |
| other | AC * 14 |
ソースコード
#include <cstdio>
#include <vector>
#include <iostream>
#include <deque>
#include <queue>
#include <tuple>
#include <map>
#include <set>
#include <algorithm>
#include <string>
#include <iomanip>
#include <bit>
#include <numeric>
#include <cassert>
#include <functional>
using namespace std;
//Integer-Related
typedef long long i64;
typedef unsigned long long ui64;
//vector-Related
template<typename T>
using vv = vector<vector<T>>;
template<typename T>
using vvv = vector<vector<vector<T>>>;
typedef vector<i64> vi64;
typedef vector<bool> vbool;
typedef vv<i64> vvi64;
typedef vv<bool> vvbool;
typedef vvv<i64> vvvi64;
typedef vvv<bool> vvvbool;
typedef pair<i64, i64> pi64;
typedef vector<string> vstr;
//これで最大値優先
template<typename Val_T, typename Pred = less<Val_T>>
using prque = priority_queue<Val_T, vector<Val_T>, Pred>;
//set-Related
#include <unordered_set>
typedef set<i64> si64;
typedef multiset<i64> msi64;
typedef unordered_set<i64> usi64;
//Calculation-Related
inline i64 rm(const i64 l, const i64 r) {
i64 val = l % r;
if (val >= 0) {
return val;
}
else {
return val + r;
}
}
template<typename T>
T r_accumulate(const vector<T>& vec) {
return std::accumulate(vec.begin(), vec.end(), T{});
}
template <typename T>
void r_insert(vector<T>& to, vector<T>& from) {
ranges::copy(from, back_inserter(to));
}
constexpr std::string repeater3030(const std::string& s, int number) {
std::string cur = "";
for (i64 i = 0; i < number; i++)
{
cur += s;
}
return cur;
}
constexpr std::string repeater3030(const char& c, int number) {
string s(1, c);
return repeater3030(s, number);
}
constexpr i64 pow_i64(i64 base, i64 exp) {
i64 res = 1LL;
while (exp > 0LL)
{
if (exp & 1) {
res *= base;
}
exp >>= 1LL;
base *= base;
}
return res;
}
template<typename T>
T eqmin(T& a, T b) {
a = min(a, b);
return a;
}
template<typename T>
T eqmax(T& a, T b) {
a = max(a, b);
return a;
}
//Output-Related
template <typename T, typename U>
std::ostream& operator<<(std::ostream& os, const std::pair<T, U>& p) {
os << "(" << p.first << ", " << p.second << ")";
return os;
}
template<typename T>
inline void output(const T elem) {
std::cout << elem << std::endl;
}
#ifndef __INTELLISENSE__
template<typename T1, typename T2>
inline void output(const pair<T1, T2> elem) {
std::cout << "(" << elem.first << "," << elem.second << ")" << std::endl;
}
template<typename T>
inline void output(const vector<T>& vec) {
for (T elem : vec) {
std::cout << elem << " ";
}
std::cout << std::endl;
}
template<typename T>
inline void output(const vector<vector<T>>& vvec) {
for (vector<T> vec : vvec) {
std::cout << "(";
for (T elem : vec) {
std::cout << elem << " ";
}
std::cout << ")";
}
std::cout << std::endl;
}
template<typename T>
inline void output(const vector<vector<vector<T>>>& vvvec) {
for (vector<vector<T>> vvec : vvvec)
{
std::cout << "[";
for (vector<T> vec : vvec) {
std::cout << "(";
for (T elem : vec) {
std::cout << elem << " ";
}
std::cout << ")";
}
std::cout << "]" << std::endl;
}
}
#endif
template<typename T>
inline void output_iter(const T& iter) {
for (auto&& elem : iter)
{
std::cout << elem << " ";
}
std::cout << std::endl;
}
/**
* ACLibrary-fewnwicktree
* Ref : https://atcoder.github.io/ac-library/master/document_ja/
*/
/**
* ACLibrary-internaltypetraits
* Ref : https://atcoder.github.io/ac-library/master/document_ja/
*/
#include <type_traits>
namespace atcoder {
namespace internal {
#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
typename std::conditional<std::is_same<T, __int128_t>::value ||
std::is_same<T, __int128>::value,
std::true_type,
std::false_type>::type;
template <class T>
using is_unsigned_int128 =
typename std::conditional<std::is_same<T, __uint128_t>::value ||
std::is_same<T, unsigned __int128>::value,
std::true_type,
std::false_type>::type;
template <class T>
using make_unsigned_int128 =
typename std::conditional<std::is_same<T, __int128_t>::value,
__uint128_t,
unsigned __int128>;
template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
is_signed_int128<T>::value ||
is_unsigned_int128<T>::value,
std::true_type,
std::false_type>::type;
template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
std::is_signed<T>::value) ||
is_signed_int128<T>::value,
std::true_type,
std::false_type>::type;
template <class T>
using is_unsigned_int =
typename std::conditional<(is_integral<T>::value &&
std::is_unsigned<T>::value) ||
is_unsigned_int128<T>::value,
std::true_type,
std::false_type>::type;
template <class T>
using to_unsigned = typename std::conditional<
is_signed_int128<T>::value,
make_unsigned_int128<T>,
typename std::conditional<std::is_signed<T>::value,
std::make_unsigned<T>,
std::common_type<T>>::type>::type;
#else
template <class T> using is_integral = typename std::is_integral<T>;
template <class T>
using is_signed_int =
typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
std::true_type,
std::false_type>::type;
template <class T>
using is_unsigned_int =
typename std::conditional<is_integral<T>::value &&
std::is_unsigned<T>::value,
std::true_type,
std::false_type>::type;
template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
std::make_unsigned<T>,
std::common_type<T>>::type;
#endif
template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;
template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;
template <class T> using to_unsigned_t = typename to_unsigned<T>::type;
} // namespace internal
} // namespace atcoder
namespace atcoder {
// Reference: https://en.wikipedia.org/wiki/Fenwick_tree
template <class T> struct fenwick_tree {
using U = internal::to_unsigned_t<T>;
public:
fenwick_tree() : _n(0) {}
explicit fenwick_tree(int n) : _n(n), data(n) {}
void add(int p, T x) {
assert(0 <= p && p < _n);
p++;
while (p <= _n) {
data[p - 1] += U(x);
p += p & -p;
}
}
T sum(int l, int r) {
assert(0 <= l && l <= r && r <= _n);
return sum(r) - sum(l);
}
private:
int _n;
std::vector<U> data;
U sum(int r) {
U s = 0;
while (r > 0) {
s += data[r - 1];
r -= r & -r;
}
return s;
}
};
} // namespace atcoder
/**
* ACLibrary-segtree
* Ref : https://atcoder.github.io/ac-library/master/document_ja/
*/
/**
* ACLibrary-internalbit
* Ref : https://atcoder.github.io/ac-library/master/document_ja/
*/
#ifdef _MSC_VER
#include <intrin.h>
#endif
#if __cplusplus >= 202002L
#endif
namespace atcoder {
namespace internal {
#if __cplusplus >= 202002L
using std::bit_ceil;
#else
// @return same with std::bit::bit_ceil
unsigned int bit_ceil(unsigned int n) {
unsigned int x = 1;
while (x < (unsigned int)(n)) x *= 2;
return x;
}
#endif
// @param n `1 <= n`
// @return same with std::bit::countr_zero
int countr_zero(unsigned int n) {
#ifdef _MSC_VER
unsigned long index;
_BitScanForward(&index, n);
return index;
#else
return __builtin_ctz(n);
#endif
}
// @param n `1 <= n`
// @return same with std::bit::countr_zero
constexpr int countr_zero_constexpr(unsigned int n) {
int x = 0;
while (!(n & (1 << x))) x++;
return x;
}
} // namespace internal
} // namespace atcoder
namespace atcoder {
#if __cplusplus >= 201703L
template <class S, auto op, auto e> struct segtree {
static_assert(std::is_convertible_v<decltype(op), std::function<S(S, S)>>,
"op must work as S(S, S)");
static_assert(std::is_convertible_v<decltype(e), std::function<S()>>,
"e must work as S()");
#else
template <class S, S (*op)(S, S), S (*e)()> struct segtree {
#endif
public:
segtree() : segtree(0) {}
explicit segtree(int n) : segtree(std::vector<S>(n, e())) {}
explicit segtree(const std::vector<S>& v) : _n(int(v.size())) {
size = (int)internal::bit_ceil((unsigned int)(_n));
log = internal::countr_zero((unsigned int)size);
d = std::vector<S>(2 * size, e());
for (int i = 0; i < _n; i++) d[size + i] = v[i];
for (int i = size - 1; i >= 1; i--) {
update(i);
}
}
void set(int p, S x) {
assert(0 <= p && p < _n);
p += size;
d[p] = x;
for (int i = 1; i <= log; i++) update(p >> i);
}
S get(int p) const {
assert(0 <= p && p < _n);
return d[p + size];
}
S prod(int l, int r) const {
assert(0 <= l && l <= r && r <= _n);
S sml = e(), smr = e();
l += size;
r += size;
while (l < r) {
if (l & 1) sml = op(sml, d[l++]);
if (r & 1) smr = op(d[--r], smr);
l >>= 1;
r >>= 1;
}
return op(sml, smr);
}
S all_prod() const { return d[1]; }
template <bool (*f)(S)> int max_right(int l) const {
return max_right(l, [](S x) { return f(x); });
}
template <class F> int max_right(int l, F f) const {
assert(0 <= l && l <= _n);
assert(f(e()));
if (l == _n) return _n;
l += size;
S sm = e();
do {
while (l % 2 == 0) l >>= 1;
if (!f(op(sm, d[l]))) {
while (l < size) {
l = (2 * l);
if (f(op(sm, d[l]))) {
sm = op(sm, d[l]);
l++;
}
}
return l - size;
}
sm = op(sm, d[l]);
l++;
} while ((l & -l) != l);
return _n;
}
template <bool (*f)(S)> int min_left(int r) const {
return min_left(r, [](S x) { return f(x); });
}
template <class F> int min_left(int r, F f) const {
assert(0 <= r && r <= _n);
assert(f(e()));
if (r == 0) return 0;
r += size;
S sm = e();
do {
r--;
while (r > 1 && (r % 2)) r >>= 1;
if (!f(op(d[r], sm))) {
while (r < size) {
r = (2 * r + 1);
if (f(op(d[r], sm))) {
sm = op(d[r], sm);
r--;
}
}
return r + 1 - size;
}
sm = op(d[r], sm);
} while ((r & -r) != r);
return 0;
}
private:
int _n, size, log;
std::vector<S> d;
void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
};
} // namespace atcoder
using namespace atcoder;
/**
* Graph一式
* Author : WhiteKnight
*/
struct Dest {
i64 to;
i64 cost;
};
typedef vector<vector<Dest>> wgraphList;//Weighted,List
typedef vector<vector<i64>> sgraphList;//Simple,List
typedef vector<Dest> vedge;
typedef vvi64 wgraphMat;//Weighted,Matrix
wgraphList translate_simple_weight(sgraphList graph) {
i64 N = graph.size();
wgraphList res(N);
for (i64 i = 0; i < N; i++)
{
for (auto&& e : graph[i])
{
res[i].push_back({e,1});
}
}
return res;
}
//コストを無視し構造のみのグラフを返す
sgraphList translate_weight_simple(wgraphList graph){
i64 N = graph.size();
sgraphList res(N);
for (i64 i = 0; i < N; i++)
{
for (auto&& e : graph[i])
{
res[i].push_back(e.to);
}
}
return res;
}
template<i64 INF>
wgraphList translate_mat_list(wgraphMat graph){
i64 N = graph.size();
wgraphList res(N);
for (i64 i = 0; i < N; i++)
{
for (i64 j = 0; j < N; j++)
{
if(graph[i][j] >= INF){
continue;
}
res[i].push_back({ j,graph[i][j] });
}
}
return res;
}
//Main Flow
/**
* Stern-Brocot-Tree
* Author: WhiteKnight
*/
struct Rational{
i64 num;
i64 dom;
};
struct SternBrocotTree{
private:
//max_dom:included,val:included
//first:左,second:右
pair<Rational,Rational> get_nearest(i64 max_dom, Rational val){
assert(val.dom > 0);
assert(max_dom >= 1);
Rational l = {0,1};
Rational r = {1,0};
Rational cur = {1,1};
pair<Rational,Rational> res = { cur,cur };
while (true)
{
if(cur.num*val.dom < val.num*cur.dom){
//to right
i64 dp_x = (cur.dom*val.num - cur.num*val.dom)/(r.num*val.dom - r.dom*val.num);
if((cur.dom*val.num - cur.num*val.dom) != (r.num*val.dom - r.dom*val.num)){
dp_x++;
}
bool stopper = false;
if(r.dom > 0){
stopper = (max_dom - cur.dom) / r.dom < dp_x;
eqmin(dp_x, (max_dom - cur.dom) / r.dom);
}
assert(dp_x >= 0);
if(dp_x == 0){
break;
}
cur.num += dp_x * r.num;
cur.dom += dp_x * r.dom;
l.num = cur.num - r.num;
l.dom = cur.dom - r.dom;
if(stopper){
res.first = cur;
break;
}else{
res.first = l;
res.second = cur;
}
}else if(cur.num*val.dom == val.num*cur.dom){
res.first = cur;
res.second = cur;
return res;
}else{
//to left
i64 dp_x = (cur.num*val.dom - val.num*cur.dom)/(val.num*l.dom-l.num*val.dom);
if((cur.num*val.dom - val.num*cur.dom) != (val.num*l.dom-l.num*val.dom)){
dp_x++;
}
bool stopper = (max_dom - cur.dom) / l.dom < dp_x;
eqmin(dp_x, (max_dom - cur.dom) / l.dom);
assert(dp_x >= 0);
if(dp_x == 0){
break;
}
cur.num += dp_x * l.num;
cur.dom += dp_x * l.dom;
r.num = cur.num - l.num;
r.dom = cur.dom - l.dom;
if(stopper){
res.second = cur;
break;
}else{
res.second = r;
res.first = cur;
}
}
}
return res;
}
public:
//max_dom:included,val:included
Rational left_nearest(i64 max_dom, Rational val){
auto res = get_nearest(max_dom,val);
return res.first;
}
//max_dom:included,val:included
Rational right_nearest(i64 max_dom, Rational val){
auto res = get_nearest(max_dom,val);
return res.second;
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout << setprecision(15);
i64 P, Q;
cin >> P >> Q;
SternBrocotTree sbt;
auto R = sbt.right_nearest(Q-1,{P,Q});
auto L = sbt.left_nearest(Q-1,{P,Q});
output(R.dom+R.num+L.dom+L.num);
return 0;
}