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;
}
上一篇:Linux基础命令find


下一篇:字节跳动不讲武德,居然笔试的时候出这种题目……