zoukankan      html  css  js  c++  java
  • 数学技巧与方法

    10.1.1 欧几里德算法和唯一分解定理

    除法表达式。给出一个这样的除法表达式:(X_1/X_2/X_3 / …/ X_k),其中(X_i)是正整数。除法表达式应当按照从左到右的顺序求和,例如,表达式(1/2/1/2)的值为(1/4)。但可以在表达式中嵌入括号以改变计算顺序,例如,表达式(frac{1/2}{1/2})的值为1。
    输入(X_1, X_2, …, X_k),判断是否可以通过添加括号,使表达式的值为整数。K≤10000,Xi≤109。
    【分析】
    表达式的值一定可以写成A/B的形式:A是其中一些Xi的乘积,而B是其他数的乘积。不难发现,X2必须放在分母位置,那其他数呢?
    幸运的是,其他数都可以在分子位置:

    接下来的问题就变成了:判断E是否为整数。
    第1种方法是利用前面介绍的高精度运算:k次乘法加一次除法。显然,这个方法是正确的,但却比较麻烦。
    第2种方法是利用唯一分解定理,把X2写成若干素数相乘的形式:

    然后依次判断每个是否是(X_1,X_3,X_4…X_k)的约数。这次不用高精度乘法了,只需把所有Xi中pi的指数加起来。如果结果比ai小,说明还会有pi约不掉,因此E不是整数。这种方法在第5章中已经用过,这里不再赘述。
    第3种方法是直接约分:每次约掉Xi和X2的最大公约数gcd(Xi, X2),则当且仅当约分结束后X2=1时E为整数,程序如下:

    int judge(int* X) {
          X[2] /= gcd(X[2], X[1]);
          for(int i = 3; i <= k; i++) X[2] /= gcd(X[i], X[2]);
          return X[2] == 1;
    }
    

    整个算法的时间效率取决于这里的gcd算法。尽管依次试除也能得到正确的结果,但还有一个简单、高效,而且相当优美的算法——辗转相除法。它也许是最广为人知的数论算法。
    辗转相除法的关键在于如下恒等式:gcd(a,b) = gcd(b, a mod b)。它和边界条件gcd(a, 0)=a一起构成了下面的程序:

    int gcd(int a, int b) {    
        return b == 0 ? a : gcd(b, a%b);
    }
    

    这个算法称为欧几里德算法(Euclid algorithm)。既然是递归,那么免不了问一句:会栈溢出吗?答案是不会。可以证明,gcd函数的递归层数不超过(4.785lgN + 1.6723),其中(N=max{a,b})。值得一提的是,让gcd递归层数最多的是(gcd(Fn,Fn-1)),其中Fn是后文要介绍的Fibonacci数。
    利用gcd还可以求出两个整数a和b的最小公倍数lcm(a,b)。这个结论很容易由唯一分解定理得到。

    由此不难验证(gcd(a,b)*lcm(a,b)=a*b)。不过即使有了公式也不要大意。如果把lcm写成a * b/gcd(a,b),可能会因此丢掉不少分数——a*b可能会溢出!正确的写法是先除后乘,即a/gcd(a,b) * b。这样一来,只要题面上保证最终结果在int范围之内,这个函数就不会出错。但前一份代码却不是这样:即使最终答案在int范围之内,也有可能中间过程越界。注意这样的细节,毕竟算法竞赛不是数学竞赛。

  • 相关阅读:
    Silverlight 3中param参数列表汇总
    在Silverlight中使用SmoothStreamingMediaElement创建Smooth Streaming播放器
    动态指定任意类型的ObjectDataSource对象的查询参数
    JQuery Ajax通过Handler访问外部XML数据
    在Excel中输入特殊字符
    SQL Server 2008禁止修改表结构的解决办法
    在xslt中实现split方法对查询字符串进行分隔
    xslt中的foreach排序
    在页面上传递参数给Silverlight插件
    [轉]Log Explorer for SQL Server 4.2
  • 原文地址:https://www.cnblogs.com/Douglas-Zhou/p/math_fj.html
Copyright © 2011-2022 走看看