• 埃及分数


    洛谷(诡异的题目链接)

    一本通在线评测

    loj Linux版本

    Solution

    因为不知道分数个数,可以无限凑,所以考虑迭代加深搜索。每次枚举一个 std,如果当前步数超过 std 就 return;一旦用 std 步成功凑出就 break,输出结果。

    需要注意的是,同一个 std 第一次找到的是“字典序最小”的解,而不是“最大数最小的解”。所以对于每一个 std,都需要找到所有可能的解,判断取出最大值最小的一个。

    现在 dfs 枚举分母的上下界还未确定。设当前还有 (frac{a}{b}) 的分数未凑出,当前枚举的分母为 (i)

    下界

    (1.) 一个显然的优化就是每次按照递增顺序枚举,所以初始下界应该是 last+1。

    (2.) 如果分母 (i) 过小,(i) 的倒数超过了 (frac{a}{b}),继续搜下去是没有意义的,这种情况需要裁掉。(frac{1}{i}>frac{a}{b})(i>frac{b}{a})

    总结一下上面两条,循环的下界是 (max(last+1, frac{b}{a}))

    上界

    因为分数的个数已确定为 (std),设当前还能放 (p) 个分数;如果分母过大,分数过小,且往后的每一个分数都比它小,会导致 (p) 个分数凑完一定小于输入的分数。所以 (p*frac{1}{i}>a/b),这个式子也可以写成 (i<frac{b*p}{a})。这样就得出了循环的上界。

    到这里程序就基本写完了。但是要注意循环上界的小于号(不是小于等于),它不允许最后一个分数加进来;因此我们在上一步就应该提前计算出最后一个分数,判断它是否合法。

    Code

     #include <iostream>
     #include <cstring>
     #include <cstdio>
     #include <cmath>
     #include <algorithm>
     using namespace std;
     
     const int N = 233333;
     
     struct Add { long long a, b; } X;
     long long res = 1e17, suc = 0, id = 0, ans[N], use[N];
     
     long long gcd(long long x, long long y)
     {
         if(x < y) swap(x, y);
         if(x % y == 0) return y;
         else return gcd(y, x % y);
     }
     long long lcm(long long x, long long y) { return (x * y) / gcd(x, y); }
     
     Add ad(Add x, Add y, long long k)
     {
         Add tmp;
         long long lc = lcm(x.a, y.a);
         tmp.a = lc;
         if(k == 0)
             tmp.b = (lc / x.a) * x.b + (lc / y.a) * y.b;
         else
             tmp.b = (lc / x.a) * x.b - (lc / y.a) * y.b;
         long long gc = gcd(tmp.a, abs(tmp.b));
         if(gc != 1)
         {
             tmp.a /= gc;
             tmp.b /= gc;
         }
         if(tmp.a == 0) tmp.a = 1;
         return tmp;
     }
     
     void dfs(Add sum, int std, int stp)
     {
         Add st = ad(X, sum, 1);
         if(st.b <= 0) return ;
         if(stp == std)
         {
             if(st.b != 1 || st.a < use[std - 1]) return ;
             use[stp] = st.a;
             if(res > use[std])
             {
                 res = use[std];
                 suc = 1;
                 for(int i = 1; i <= std; i++)
                     ans[i] = use[i];
             }
             return ;
         }
         for(int i = max(use[stp - 1] + 1, st.a / st.b + 1); i < (std - stp + 1) * st.a / st.b; i++)
         {
             Add now;
             now.a = i, now.b = 1;
             use[stp] = i;
             dfs(ad(now, sum, 0), std, stp + 1);
         }
     }
     
     int main()
     {
         cin >> X.b >> X.a;
         memset(use, 0, sizeof(use));
         memset(ans, 0, sizeof(ans));
         long long x = gcd(X.b, X.a);
         X.a /= x;
         X.b /= x;
         for(int i = 2; i <= 233; i++)
         {
             Add fir;
             res = 1e16;
             fir.a = 1, fir.b = 0;
             dfs(fir, i, 1);
             if(suc) { id = i; break; }
         }
         for(int i = 1; i <= id; i++) cout << ans[i] << " ";
         cout << endl;
         return 0;
     }
    
  • 相关阅读:
    企业微信开发基本步骤
    简单的企业微信开发 前后端
    真分页
    企业微信“三次握手”
    Android项目的图标
    Android项目的目录结构
    Android系统提供了哪些东西,供我们可以开发出优秀的应用程序
    Android中的四层架构,五块区域
    MySQL中的concat函数
    Activity生命周期
  • 原文地址:https://www.cnblogs.com/Andy-park/p/13451227.html
Copyright © 2020-2023  润新知