• 【板子】gcd、exgcd、乘法逆元、快速幂、快速乘、筛素数、快速求逆元、组合数


    1.gcd

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

    2.扩展gcd )extend great common divisor

    复制代码
    ll exgcd(ll l,ll r,ll &x,ll &y)
    {
        if(r==0){x=1;y=0;return l;}
        else
        {
            ll d=exgcd(r,l%r,y,x);
            y-=l/r*x;
            return d;
        }
    }
    复制代码
    void ex_gcd(ll a, ll b, ll &d, ll &x, ll &y) // 扩展欧几里得  
    {  
        if(!b) { d = a; x = 1; y = 0;}  
        else { ex_gcd(b, a%b, d, y, x); y -= x*(a/b);}  
    }  

    3.求a关于m的乘法逆元

    复制代码
    ll mod_inverse(ll a,ll m){
        ll x,y;
        if(exgcd(a,m,x,y)==1)//ax+my=1
            return (x%m+m)%m;
        return -1;//不存在
    }
    复制代码

    补充:求逆元还可以用

    ans=abmodm=(amod(mb))/bans=abmodm=(amod(m⋅b))/b

    4.快速幂quick power

    复制代码
    ll qpow(ll a,ll b,ll m){
        ll ans=1;
        ll k=a;
        while(b){
            if(b&1)ans=ans*k%m;
            k=k*k%m;
            b>>=1;
        }
        return ans;
    }
    复制代码
    ll func(ll a,ll b,ll c)     //a*b%c
    {
        long long ret = 0;
        while (b)
        {
            if (b & 1)
                ret = (ret + a) % c;
            a = 2 * a % c;
            b >>= 1;
        }
        return ret;
    }
    
    ll pow_mod(ll a,ll b,ll MOD)
    {
        if (a==1)   return 1;
        ll t=a%MOD,ans=1;
        while(b)
        {
            if (b&1)
                ans=func(ans,t,MOD);
            t=func(t,t,MOD);
            b>>=1;
        }
        return ans;
    }
    View Code

    5.快速乘,直接乘会爆ll时需要它,也叫二分乘法。

    复制代码
    ll qmul(ll a,ll b,ll m){
        ll ans=0;
        ll k=a;
        ll f=1;//f是用来存负号的
        if(k<0){f=-1;k=-k;}
        if(b<0){f*=-1;b=-b;}
        while(b){
            if(b&1)
                ans=(ans+k)%m;
            k=(k+k)%m;
            b>>=1;
        }
        return ans*f;
    }
    复制代码

    6.中国剩余定理CRT (x=ai mod mi)

    复制代码
     
     
    //两个数组a(除数),m(余数)
    //中国剩余定理一般要用到两个数组
    //一般是计算多少数
    //一般用于互质
    ll china(ll n, ll *a,ll *m) {
        ll M=1,y,x=0,d;
        for(ll i = 1; i <= n; i++) M *= m[i];
        for(ll i = 1; i <= n; i++) {
            ll w = M /m[i];
            exgcd(m[i], w, d, y);//m[i]*d+w*y=1
            x = (x + y*w*a[i]) % M;
        }
        return (x+M)%M;
    }
     

    所以非互质的就要用到ecgcd

    7.筛素数,全局:int cnt,prime[N],p[N];

    复制代码
    void isprime()
    {
        cnt = 0;
        memset(prime,true,sizeof(prime));
        for(int i=2; i<N; i++)
        {
            if(prime[i])
            {
                p[cnt++] = i;
                for(int j=i+i; j<N; j+=i)
                    prime[j] = false;
            }
        }
    }
    复制代码

     miller rabin  O(1)

      typedef long long ll;
      ll ModMul(ll a,ll b,ll n)//快速积取模 a*b%n
      {
          ll ans=0;
          while(b)
          {
              if(b&1)
                ans=(ans+a)%n;
              a=(a+a)%n;
              b>>=1;
          }
          return ans;
      }
      ll ModExp(ll a,ll b,ll n)//快速幂取模 a^b%n
      {
          ll ans=1;
          while(b)
          {
              if(b&1)
                ans=ModMul(ans,a,n);
              a=ModMul(a,a,n);
              b>>=1;
          }
          return ans;
      }
      bool miller_rabin(ll n)//Miller-Rabin素数检测算法
      {
          ll i,j,a,x,y,t,u,s=10;
          if(n==2)
            return true;
          if(n<2||!(n&1))
            return false;
          for(t=0,u=n-1;!(u&1);t++,u>>=1);//n-1=u*2^t
          for(i=0;i<s;i++)
          {
              a=rand()%(n-1)+1;
              x=ModExp(a,u,n);
              for(j=0;j<t;j++)
              {
                  y=ModMul(x,x,n);
                  if(y==1&&x!=1&&x!=n-1)
                    return false;
                  x=y;
              }
              if(x!=1)
                return false;
          }
          return true;
      }

    8.快速计算逆元

    补充:>>关于快速算逆元的递推式的证明<< 

    复制代码
    void inverse(){
        inv[1] = 1;
        for(int i=2;i<N;i++)
        {
            if(i >= M) break;
            inv[i] = (M-M/i)*inv[M%i]%M;
        }
    }
    复制代码

    9.组合数取模

    n和m 10^5时,预处理出逆元和阶乘

    复制代码
    ll fac[N]={1,1},inv[N]={1,1},f[N]={1,1};
    ll C(ll a,ll b){
        if(b>a)return 0;
        return fac[a]*inv[b]%M*inv[a-b]%M;
    }
    void init(){//快速计算阶乘的逆元
        for(int i=2;i<N;i++){
            fac[i]=fac[i-1]*i%M;
            f[i]=(M-M/i)*f[M%i]%M;
            inv[i]=inv[i-1]*f[i]%M;
        }
    }
    复制代码

    n较大10^9,但是m较小10^5时,

    复制代码
    ll C(ll n,ll m){
        if(m>n)return 0;
        ll ans=1;
        for(int i=1;i<=m;i++)
            ans=ans*(n-i+1)%M*qpow(i,M-2,M)%M;
        return ans;
    }
    复制代码

    n和m特别大10^18时但是p较小10^5时用lucas

    10.Lucas大组合取模 

    复制代码
    #define N 100005
    #define M 100007
    ll n,m,fac[N]={1};
    ll C(ll n,ll m){
        if(m>n)return 0;
        return fac[n]*qpow(fac[m],M-2,M)%M*qpow(fac[n-m],M-2,M)%M;//费马小定理求逆元
    }
    ll lucas(ll n,ll m){
        if(!m)return 1;
        return(C(n%M,m%M)*lucas(n/M,m/M))%M;
    }
    void init(){
        for(int i=1;i<=M;i++)
            fac[i]=fac[i-1]*i%M;
    }
    复制代码

     

     11.欧拉函数

    
    
    ll mul(ll x, ll y) {
        return 1ll * x * y % mod;
    }

    ll Phi(ll N) { ll ans
    = 1; for(ll i = 2; i * i <= N; i++) { if(!(N % i)) { ans = mul(ans, i - 1); N /= i; while(!(N % i)) ans *= i, N /= i; } } if(N ^ 1) ans *= N - 1; return ans; }
  • 相关阅读:
    昇腾AI处理器软件栈--任务调度器(TS)
    [转]shopnc 版权问题
    关于对接诸葛IO 解决的问题
    Mysql中like查询中存在反斜杠的解决方法
    关于TP,PHP和shopnc 的cookie
    TypeError: document.getElementById(…).submit is not a function解决
    关于图片上传的 相对路径出现问题
    Android 通讯录
    关于kindedit和 Uedit后者兼容前者
    Handler机制
  • 原文地址:https://www.cnblogs.com/DWVictor/p/10237455.html
Copyright © 2020-2023  润新知