[10 08]T1有理树sbt

题目描述

小B最近学习了 S t e r n − B r o c o t Stern-Brocot SternBrocot t r e e tree tree这是一种能表示所有正有理数的结构,如下图
在这里插入图片描述
不难发现所有正有理数形成了一颗以 1 1 \frac{1}{1} 11为根的树,一个树的位置可以用字符串表示,即从根找到这个数在树上的位置,向左用L表示向右用R表示,根节点对应的字符串为空串。
现给出a,b, 求 a b \frac{a}{b} ba在树中的位置

样例:
输入
10 6
输出
RLR

对于30%的数据,字符串长度≤20。
对于全部的数据a,b≤106

刚开始我以为很难,没有理解出sbt的意思。
于是就想着暴力建树然后在树上暴力查找。
emm,对于一个节点,我们如果能维护出他左边和右边需要加上的数,我们就能建立出这个节点所表示的有理数,
这个节点的左右需要加的数取决于它是左子节点还是右子节点,同时我们还需要父亲的父亲的信息,我们可以在建立完父亲节点的时候处理完这些信息。
然后我们就可以快乐的爆搜了。
为了防止我们的搜索连30都过不去,我们考虑优化,
那么我们观察这颗树,从 1 1 \frac{1}{1} 11开始,左边的比右边小,最左边的一直递减,最右边一直递增,
那我们在观察任意一个节点,发现每个节点都满足像刚才根节点那样的性质,即左子节点比右子节点小
于是我们在找的时候可以直接判断自己要找的方向,建树也不用全建出来,直接建一条链,直通答案的那种。
但是我们再稍稍想一下会发现,一个点把信息处理好打包给下一个点时,这个点就没用了,那我们岂不是连树也不用建了?
直接搜索,维护出自己需要的信息,然后O(n)就过了这道题。

#include<bits/stdc++.h>

#define MAXN 1000010
#define N 100010
#define rg register
#define INF 0x3f3f3f3f
#define gtc() getchar()
#define ll long long

using namespace std;

template<class T>
inline void read(T &s){
	T w = 1, ch = gtc(); s = 0;
	while(!isdigit(ch)){if(ch == '-') w = -1; ch = gtc();}
	while(isdigit(ch)){s = s * 10 + ch - '0'; ch = gtc();}
	s *= w;
}

inline int gcd(int a, int b){
	return a % b == 0 ? b : gcd(b, a % b);
}

int n, m;

struct node{
	int son, mt;
	string way;
}t[MAXN];

int xx;//nl,nm是做边需要加的分子和分母,nr,nn同理,fs,fm是当前节点的信息
//这个搜索是建树的函数直接魔改过来的(看函数名就能看出来)有一些东西是不需要的
void build(int k, int nl, int nm, int nr, int nn, int rot, string way, int fs, int fm){
	if(fs == n && fm == m){
		cout << way << endl;
		xx = -1; return ;
	}
	if(rot > xx) return ;	
	if(fs * m > fm * n){
		build(k << 1, nl, nm, fs, fm, rot + 1, way+"L", fs + nl, fm + nm);
	}
	else build(k << 1 | 1, fs, fm, nr, nn, rot + 1, way+"R", fs + nr, fm + nn);
}
int main()
{
	freopen("sbt.in", "r", stdin);
	freopen("sbt.out", "w", stdout);
	read(n), read(m);
	int k = n > m ? gcd(n, m) : gcd(m, n);
	//n,m不互质,我们要先约分
	n /= k, m /= k;
	
	xx = n > m ? m + 1 : n + 1;
	
	if(n == m || n == 0 || m == 0){
		puts(""); return 0;
	}
	if(n > m){
		build(1<<1|1, 1, 1, 1, 0, 1, "R", 2, 1);
	}
	else build(1<<1, 0, 1, 1, 1, 1, "L", 1, 2);
	
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BIGBIGPPT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值