• [CodeVs1515]跳(lucas定理+费马小定理)


          嘿嘿嘿好久没写数学题了,偶尔看到一道写一写。。。 

          题目大意:一个(n+1)*(m+1)【0<=n, m<=10^12,n*m<=10^12】的矩阵,C(0,0)=1,C(x,y)=C(x-1,y)+C(x,y-1),求从0,0走到n,m路上最小权值(即为前面的C)和mod 10^9+7。

          看到这个C(x,y)=C(x-1,y)+C(x,y-1),第一反应就是杨辉三角,所以这个矩阵其实就是一个由组合数组成的矩阵,第i行第j列的权值为C(i+j,j)【注意这个矩形起点是(0,0)】。

          我们可以发现(0,0)~(n,0)和(0,0)~(0,m)上都是1,所以我们肯定选择走这条路,而且要走长的那条,不过我们只走(0,0)~(n-1,0)或(0,0)~(0,m-1),因为(n,0)或(0,m)接下来要算到,反正没有太大影响,那么这一段的权值和为max(n,m)。接下来就是剩下的那一段了,显然往上和往左走肯定是亏的,所以我们继续往终点走,而这一段的路径则为C(max(n,m)+i,i)【0≤i≤min(n,m)】的和。看不懂的话看看样例,如下图:                       

          上图的1和3就是C(2+0,0)和C(2+1,1)的值,其实只要把矩阵顺时针旋转45°就是杨辉三角了,而C(max(n,m)+i,i)【0≤i≤min(n,m)】的和就是C(n+m+1,min(n,m)),证明略。所以这个矩阵的最短路径则为max(n,m)+C(n+m+1,min(n,m))。这题数据范围是比较猎奇的,但是毋庸置疑的是暴力求组合数取模肯定是不行的啊,这里我们就要用到lucas定理了,lucas定理即C(a,b)mod p=C(a/p,b/p)*C(a mod p,b mod p),然后就用费马小定理+乘法逆元求一下组合数就行辣,然后这题就写完了,代码很短也很容易理解。

    const
      p=1000000007;
    var
      n,m,t:int64;
    
    function qp(a,b:int64):int64;//快速幂
    var
      y,t:int64;
    begin
      y:=a mod p;t:=1;
      while b>0 do
      begin
        if b and 1=1 then t:=t*y mod p;
        y:=y*y mod p;
        b:=b>>1;
      end;
      exit(t mod p);
    end;
    
    function C(a,b:int64):int64;//费马小定理+乘法逆元
    var
      i:longint;
      aa,bb:int64;
    begin
      if b>a then exit(0);
      if b>a-b then b:=a-b;
      aa:=1;bb:=1;
      for i:=1 to b do
      begin
        aa:=aa*(a-i+1) mod p;
        bb:=bb*i mod p;
      end;
      exit(aa*qp(bb,p-2) mod p);
    end;
    
    function lucas(a,b:int64):int64;//lucas定理
    begin
      exit(C(a div p,b div p)*C(a mod p,b mod p)mod p);
    end;
    
    begin
      readln(n,m);
      if n>m then
      begin
        t:=n;n:=m;m:=t;
      end;
      writeln((m+lucas(n+m+1,n))mod p);
    end.
    View Code
  • 相关阅读:
    如何提高工作效率,重复利用时间
    好记性不如烂笔头
    如何应对面试中关于“测试框架”的问题
    通宵修复BUG的思考
    工作方法的思考
    别认为那是一件简单的事情
    开发人员需要熟悉缺陷管理办法
    不了解系统功能的思考
    如何布置任务
    事事有回音
  • 原文地址:https://www.cnblogs.com/Sakits/p/5352601.html
Copyright © 2020-2023  润新知