题目
题目描述
小 ZZZ 要进行物理实验,需要 TTT 个电阻,每个电阻所需要的电阻值都可以用一个分数进行表示。
但很不幸的是,物理实验室只有阻值为 111 的电阻和电阻可以忽略不计的导线,好在这些物品有无限多个。
于是小 ZZZ 打算通过串并联的方式尝试构造自己所需要的每个电阻,对于每个电阻,小 ZZZ 都会从一个阻值为 111 的电阻开始,每次在原有的电路基础上串联或者并联一个阻值为 111 的电阻,他想知道对于自己所需要的每个阻值,最少需要使用多少个阻值为 111 的电阻才能拼出来。
输入格式
第一行为一个正整数 TTT,表示数据组数,接下来 TTT 组数据,每组数据一行两个整数 A,BA,BA,B ,表示需要一个阻值为 A/BA/BA/B 的电阻。
输出格式
对每组数据输出一行一个非负整数,表示答案。
样例输入 #1
2
2 3
5 2
样例输出 #1
3
4
【样例解释】
第一组数据中,从一个阻值为 111 的电阻开始,并联一个阻值为 111 的电阻,再串联一个阻值为 111 的电阻即可。
第二组数据中,将两个阻值为 111 的电阻并联,再串联两个阻值为 111 的电阻。
【数据规模与约定】
本题一共 101010 个测试点,每个测试点 101010 分。
第 1∼31\sim 31∼3 个测试点,满足 T,A,B≤20T,A,B≤20T,A,B≤20
所有测试点均满足 1≤T≤1000;1≤A,B≤10181≤T ≤1000 ; 1 ≤ A,B ≤ 10^{18}1≤T≤1000;1≤A,B≤1018
思路
题意大概就是用一些阴值为 111 的电阻,去串联或并联其余阴值为 111 的电阻,求出操作后最终值为 AB\frac{A}{B}BA 最少需要几个电阻。
我们设当前的阴值 QP\frac{Q}{P}PQ,则串联一个阴值为 111 的电阻后,阴值会变为 Q+PP\frac{Q+P}{P}PQ+P,并联一个阴值为 111 的电阻后,阴值会变为 QP+Q\frac{Q}{P+Q}P+QQ,可以发现要么操作一次后要么是分母加分子,要么是分子加分母。
而且我们还可以发现一个性质:我们记 f(AB)f(\frac{A}{B})f(BA) 表示让阴值成为 AB\frac{A}{B}BA 所需的电阻数,则 f(AB)=f(BA)(A>B)f(\frac{A}{B})=f(\frac{B}{A})(A>B)f(BA)=f(AB)(A>B)。
证明:我们假设 AAA 和 BBB 满足上面的性质,则说明 f(AB)=f(BA)f(\frac{A}{B})=f(\frac{B}{A})f(BA)=f(AB),那么 f(A+BA)=f(BA)+1f(\frac{A+B}{A})=f(\frac{B}{A})+1f(AA+B)=f(AB)+1,f(AA+B)=f(AB)+1f(\frac{A}{A+B})=f(\frac{A}{B})+1f(A+BA)=f(BA)+1,因为 f(AB)=f(BA)f(\frac{A}{B})=f(\frac{B}{A})f(BA)=f(AB),所以 f(A+BB)=f(AA+B)f(\frac{A+B}{B})=f(\frac{A}{A+B})f(BA+B)=f(A+BA)。而数归的起点是 A=1,B=1A=1,B=1A=1,B=1。
所以我么就可以得出我们的算法:
f(AB)={B=0 0A≥B ⌊AB⌋+f(A mod BB)A<B f(BA)f(\frac{A}{B})=\begin{cases}B=0~~~~ ~~0\\A≥B~~~ \left \lfloor \frac{A}{B} \right \rfloor+f(\frac{A\bmod B}{B}) \\A<B~~~~ f(\frac{B}{A})\end{cases}f(BA)=⎩⎨⎧B=0 0A≥B ⌊BA⌋+f(BAmodB)A<B f(AB)
容易看出这是一个递归,即可实现。
代码
#include<bits/stdc++.h>
using namespace std;
#define R register
#define ri register int
#define int long long
#define ull unsigned long long
#define lid (id<<1)
#define rid (id<<1|1)
void swap(int &x,int &y){int t=x;x=y;y=t;}
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x<y?x:y;}
const int N=2e5;
inline int read();
inline void write(int ans);
inline void put(int x,char c);
int T,a,b;
int get(int n,int m){
if(m==0)
return 0;
if(n<m)
return get(m,n);
return n/m+get(n%m,m);
}
signed main(){
T=read();
while(T--){
a=read(),b=read();
int ss=__gcd(a,b);
a/=ss;
b/=ss;
printf("%lld\n",get(a,b));
}
return 0;
}
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void write(int x){if(x<0){putchar('-');x=-x;}if(x>9){write(x/10);}putchar(x % 10+'0');return;}
inline void put(int x,char c){write(x);putchar(c);return;}