zoukankan      html  css  js  c++  java
  • 大数取余

    有一类题目会因为求出的结果太大而只要求输出对某个数m取余后的结果,而且这个m是比较小的数,比如不超过32位整数…
    而这类大数都是可以由较小的数经过某些运算得到的…
    于是我整理了一下对付几种运算的方法…包括四则运算,指数,组合数,塔函数的应对方法…

    那么就开始吧…慢慢来…
    首先是最常识的加减法:

    add_mod(a,b,m){ return ((a%m)+(b%m))%m; }

    别小看加法哦…很多用dp解的题目中靠着加法可是能达到很大的数呢…

    minus_mod(a,b,m){ return (a-b+m)%m; }

    减法…会遇到吗?

    接着是依然很简单的乘法:

    multiply_mod(a,b,m){ return ((a%m)*(b%m))%m; }

    这是当m*m不会溢出时可以用的,同时也是通常的情况…
    但是如果m*m连long long都会溢出的话…就需要把一个数一位位拆开来做了…

    multiply_mod(a,b,m){ if(b==0)return 0; return (((b&1)?a:0)+(multiply_mod(a,b>>1,m)<<1)%m)%m; }

    然后是除法,但有点限制:
    (a/b)%m
    特殊条件:m和b互质
    前提:a能被b整除
    这个有点特殊,意为虽然不知道a是多少,但是已知c,而且c=a%m,用c和b来求(a/b)%m的方法
    虽然需要m和b互质,但是不互质的话也是可以做的,因为a也一定是gcd(b,m)的倍数,具体可以看看这里

    需要用到扩展欧几里德来求…
    至于扩展欧几里德是什么…去Google一下吧…

    extend_euclid(a,b,&x0,&y0){ if(b==0){ x0=1; y0=0; return a; } r=extend_euclid(b,a%b); t=x0; x0=y0; y0=t-a/b*y0; return r; } divide_mod(a,b,m){ extend_euclid(b,m,x0,y0); return (a*(((x0%m)+m)%m))%m; }

    这个在求组合数的时候可能用到…
    不过似乎很少遇到需要用除法取余的情况呢…

    然后是更大却很简单的幂运算:
    (a^b)%m
    这是初学递归或者二分时就会遇上的一个很简单的方法,和之前的乘法差不多

    power_mod(a,b,m){ if(b==0)return 1; if(b&1)return (a*power_mod((a*a)%m,b>>1,m))%m; else return power_mod((a*a)%m,b>>1); }

    其中乘法取余会运算中溢出的话可以改成之前那个multiply_mod()

    恩…开始有趣了…下面是组合数:
    C(a,b)%m
    特殊条件:m是质数
    如果b或者a-b比较小的话,可以用之前计算(a/b)%m的方式来把组合数公式展开来计算
    不过当b和a-b与m相比很大时,有更好的方法:
    a,b在m进制下表示为 a=(ak,…,a0),b=(bk,…,b0) 0=<ai,bi<m
    于是会有这样的性质:

    C(a,b)=C(ak,bk)*...*C(a0,b0) (mod m)

    最后是难以想象的大的数…塔函数:
    (a↑↑b)%m
    这里可以看到其一些性质
    比如Project Euler 282
    Ackermann 函数就是非常恶心的大数
    第一层是很小的常数,第二层是n个a相加,也就是乘法,第三层是n个a相乘,也就是幂,第四层是n个a叠着做幂即塔函数,第k+1层是n个a做第k层运算…
    用小数字居然也能表示出如此之大的数…佩服啊…
    上一篇中也有提到:

    n>=phi(m)时,a^n=a^(n%phi(m)+phi(m)) (mod m)

    其中phi()是欧拉函数
    由于phi(x)<x,所以就算是对a↑↑b这样大的数也总会在足够短的时间内收敛,然后计算出(mod m)的值
    这个不止在塔函数中,也可以用在各种指数异常大的情况下
    特别的,在b>m的情况下,(a↑↑b)%m的值将是定值

    恩…就到这里了…

  • 相关阅读:
    luogu P1019 单词接龙
    luogu P4137 Rmq Problem / mex
    Virtualbox 修改硬盘的序列号等信息 例
    httpHandlers path="*.sky"
    Oracle告Google输了
    %STSADM% -o addsolution -filename AEMediaPlayerWebpart.wsp
    placeholder
    String强制转换为Date,freemarker标签里date数据的显示问题
    eclipse配置JDK和设置编译版本的几种方法
    httpd 系统错误 无法启动此程序,因为计算机中丢失VCRUNTIME140.dll
  • 原文地址:https://www.cnblogs.com/Wu-Shi/p/5410059.html
Copyright © 2011-2022 走看看