类欧几里得学习笔记
# 类欧几里得
类欧几里得只是复杂度同欧几里得相似,跟欧几里得没有关系。
# 引入 51Nod 1187
给出 , 找一个分数,使得,并且最小。例如:同之间,符合条件且分母最小的分数是。(如果相同,输出最小的)
下面进行分类讨论
当(递归边界1)
由于,显然有
当
可以对不等式两边同时减去,转化为情况
当(递归边界2)
显然有
其他情况
对不等式两边求倒数,得,且,转化为情况
看了上面的例题,聪明的你一定会了吧?不妨来做一下下面这道例题。
# 例题 洛谷P5170 (opens new window)
给定 分别求 答案对 998244353 取模。
# 1. 求
令
# 1.1 当或
转化为的情况
# 1.2 当
式中的方括号为艾佛森括号
,当条件成立时值为,否则为.
对不等式进行变换
再次下取整
继续对原式进行化简
上面的公式巨长,巨难写
式到式的转换:核心是通过限制转移,使得不受限制。
式到式的转换:实质上是统计大于的的个数,可以改写作
使用式进行递归求解,当时,
# 2. 求
# 3. 求
# 万能欧几里得
# AC代码
# 51Nod 1187
#include <bits/stdc++.h>
#define Android ios::sync_with_stdio(false), cin.tie(NULL)
using namespace std;
void calc(int a, int b, int c, int d, int & p, int & q){
if(a == 0){
p = 1, q = d / c + 1;
} else if(a >= b){
int delta = a / b;
calc(a%b, b, c - d*delta, d, p, q);
p += q * delta;
}else if(c > d){
p = q = 1;
}else{
calc(d, c, b, a, q, p);
}
}
void solve(){
int a, b, c, d, p, q, g;
cin >> a >> b >> c >> d;
calc(a, b, c, d, p, q);
g = __gcd(p, q);
cout << p / g << "/" << q / g << "\n";
}
signed main(){
Android;
int t; cin >> t;
while(t--) solve();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
上次更新: 2021/02/24, 03:37:30