UVA12558 埃及分数 数学知识 + 迭代加深 + dfs + 剪枝
UVA12558 埃及分数
数学知识 + 迭代加深 + dfs + 剪枝
我觉得这道题还是比较难的,反正看题解看了好长时间。
首先用迭代加深,枚举分解后的项数。
dfs时的上下界:下界为\(\lfloor \frac{b}{a} \rfloor + 1\),上界是\(a * i >= b * (maxdep - now + 1)\),其中\(i\)为当前枚举的分母,\(maxdep\)为迭代加深枚举的项数,\(dep\)为当前枚举到了第几项。证明
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
const int N = 1e5 + 5;
int t, k, flag, maxdep;
long long a, b;
int w[N], tmp[N];
set <int> q;
int judge() {
for(int i = maxdep;i >= 1; i--)
if(tmp[i] != w[i]) {
if(tmp[i] > w[i] || tmp[i] == 0) return 0;
else return 1;
}
return 1;
}
void copy() {
for(int i = 1;i <= maxdep; i++) tmp[i] = w[i];
}
int gcd(int x, int y) {
return y == 0 ? x : gcd(y, x % y);
}
void dfs(long long a, long long b, int now, long long last) {
if(now == maxdep) {
if(b % a || q.count(b / a)) return ;
w[now] = b / a;
if(!judge()) copy();
flag = 1; return ;
}
for(long long i = max(last, b / a + 1); ; i++) {
if(q.count(i)) continue;
if(i * a >= b * (maxdep - now + 1)) break;
long long na = a * i - b, nb = b * i;
long long g = gcd(na, nb);
w[now] = i; dfs(na / g, nb / g, now + 1, i + 1);
}
}
void Clear() {
flag = 0; q.clear();
memset(tmp, 0, sizeof(tmp));
}
signed main() {
t = read();
for(int l = 1;l <= t; l++) {
Clear();
a = read(); b = read(); k = read();
for(int i = 1, x;i <= k; i++) x = read(), q.insert(x);
for(maxdep = 2; ; maxdep++) {
if(flag) break;
memset(tmp, 0, sizeof(tmp));
dfs(a, b, 1, b / a + 1);
}
printf("Case %lld: %lld/%lld=1/%lld", l, a, b, tmp[1]);
for(int i = 2;i < maxdep; i++) printf("+1/%lld", tmp[i]);
printf("\n");
}
return 0;
}