【板子】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; }

 

 

转载于:https://www.cnblogs.com/DWVictor/p/10237455.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值