• 数论


    1.二项式定理


    例题:计算系数

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    const ll mo=10007;
    int a,b,k,n,m;
    ll c[1007][1007];
    ll qpow(int a,int b)
    {
      ll ans=1,base=a;
      while(b)
      {
       if(b&1)
       ans=ans*base%mo;
       base=base*base%mo;
       b>>=1; 
      }
      return ans;
    }
    int main()
    { 
     scanf("%d%d%d%d%d",&a,&b,&k,&n,&m);
     c[0][0]=1;
     for(int i=1;i<=k;i++)
     c[i][0]=c[i][i]=1;
     for(int i=1;i<=k;i++)
     {
      for(int j=1;j<i;j++)
      {
        c[i][j]=(c[i-1][j-1]+c[i-1][j])%mo;
      }
     }
     ll ans=c[k][n]*qpow(a,n)%mo*qpow(b,m)%mo;
     printf("%lld
    ",ans);
     return 0;
    }
    

    2.扩展欧几里得

    (ax+by=c)有解当且仅当(d=gcd(a,b)),且(d|c)。方程的通解为(x=frac{c}{d}x_{0}+kfrac{b}{d}),(y=frac{c}{d}y_{0}-kfrac{a}{d}),((kepsilon mathbb{Z})).

    其中(x_{0})(y_{0})的求解方法就是扩展欧几里得。

    ll exgcd(ll a,ll b,ll &x,ll &y)
    {
      if(b==0)
      {
        x=1,y=0;
        return a;
      }
      ll d=exgcd(b,a%b,x,y);
      ll tmp=x;
      x=y;
      y=tmp-y*(a/b);
      return d;//d为gcd
    }
    

    例题:同余方程

    满分作法:原式可以转化为(ax+by=1),因为保证有解,只能(gcd(a,b)=1).找到第一个正整数解,只需先求解,在加即可。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    ll a,b;
    ll xx,yy;
    ll exgcd(ll a,ll b,ll &x,ll &y)
    {
      if(b==0)
      {
       x=1,
       y=0;
       return a;
      }
      ll d=exgcd(b,a%b,x,y);
      ll tmp=x;
      x=y;
      y=tmp-y*(a/b);
      return d;
    }
    int main()
    {
     scanf("%lld%lld",&a,&b);//由题gcd(a,b)=1,否则无解 
     exgcd(a,b,xx,yy);
     while(xx<=0)
     xx+=b;
     printf("%lld
    ",xx);
     return 0;	
    }
    

    3.乘法逆元(也就是在取模意义下的除数)

    1.方法一:扩展欧几里得求逆元(适用所有)

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    ll a,p,xx,yy;
    void exgcd(ll a,ll b,ll &x,ll &y)
    {
     if(b==0)
     {
      x=1;
      y=0;
      return;
     }
     exgcd(b,a%b,x,y);
     ll tmp=x;
     x=y;
     y=tmp-y*(a/b);
    }
    int main()
    {
     scanf("%lld%lld",&a,&p);
     exgcd(a,p,xx,yy);
     xx=(xx%p+p)%p;//有可能是负数,所以要这样取模
     printf("%lld
    ",xx);
     return 0;	
    }
    

    2.快速幂(两数互质)

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    ll a,p;
    ll qpow(ll a,ll b)
    {
      ll ans=1,base=a;
      while(b){
       if(b&1)
       ans*=base,base%=p;
       base*=base,base%=p;
       b>>=1;
     }
     return ans;
    }
    
    int main()
    {
      scanf("%lld%lld",&a,&p);
      printf("%lld
    ",qpow(a,p-2)%p);
      return 0; 
    }
    

    3.求连续数(1,2,3,4,5.....)的逆元

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    const int maxm=3e6+7;
    ll p;
    int n;
    ll inv[maxm];
    int main()
    {
     scanf("%d%lld",&n,&p);
     inv[1]=1;
     printf("1
    ");
     for(int i=2;i<=n;i++)
     {
       inv[i]=(p-p/i)*inv[p%i]%p;//-p/i是负数所以+p 
       printf("%lld
    ",inv[i]);	
     } 
     return 0;	
    } 
    

    4.一个序列的逆元.

    例题:乘法逆元2

    我们设数组(a)的各项是:

    (a_1,a_2,a_3......a_n)

    则其逆元可表示为:

    (frac{1}{a_1},frac{1}{a_2},frac{1}{a_3},......frac{1}{a_n})

    我们取一个数列(s),表示:

    (s_i = a_1 * a_2 * ...... * a_i)

    其递推式为:

    (s_i = s_{i-1}*a_i)

    则:

    (frac{1}{s_i} = frac{1}{a_1 * a_2 * ...... * a_i})

    易得其递推式为:

    (frac{1}{s_{i-1}} = frac{1}{s_{i}}*a_i)

    于是(frac{1}{a_i})可以表示为

    (frac{1}{a_i}=s_{i-1}*frac{1}{s_{i}})

    其中(a_i)是已知的,(s_i)是线性递推的,而求出(frac{1}{s_n})后,可以再次线性递推出(frac{1}{s_i})。最后求出(frac{1}{a_i})

    最后用秦九韶优化即可。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    const int maxm=5e6+7;
    int n;
    inline int read()
    {
        char ch=getchar();int x=0,f=1;
        while(ch<'0' || ch>'9') {
           if(ch=='-') f=-1;
          	  ch=getchar();
        }
        while(ch<='9' && ch>='0') {
           x=x*10+ch-'0';
           ch=getchar();
        }
        return x*f;
    }
    inline ll readl() {
        char ch = getchar();
        ll x = 0, f = 1;
        while (ch < '0' || ch > '9') {
            if (ch == '-')
                f = -1;
            ch = getchar();
        }
        while (ch <= '9' && ch >= '0') {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    ll p,k,a[maxm];
    ll s[maxm];
    ll inv[maxm];
    ll ans=0;
    ll qpow(ll a,ll b)
    {
      ll ans=1,base=a;
      while(b){
       if(b&1)
       ans=ans*base,ans%=p;
       base=base*base,base%=p;
       b>>=1;
     }
     return ans;
    }
    int main()
    {
     n=read();
     p=readl();
     k=readl();
     s[0]=1;
     for(int i=1;i<=n;i++)
     a[i]=readl();
     for(int i=1;i<=n;i++)
     s[i]=a[i]*s[i-1]%p;
     inv[n]=qpow(s[n],p-2);
     for(int i=n-1;i>=1;i--)
     inv[i]=inv[i+1]*a[i+1]%p;
     for(int i=n;i>=1;i--)
     {
      ll node=inv[i]*s[i-1]%p;
      ans=((ans+node)%p*k%p);
     }
     printf("%lld
    ",ans);
     return 0;
    }
    

    5.组合数取模(Lucas定理)

    (Lucas_{m}^n equiv Lucas_{m/p}^{n/p} * C_{n mod p}^{m mod p} pmod p)

    例题:卢卡斯定理

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    const int maxm=2e5+7;
    ll n,m,p;
    int t;
    ll inv[maxm];
    ll qpow(ll a,ll b)
    {
     ll ans=1,base=a;
     while(b)
     {
       if(b&1) ans=base*ans%p;
       base=base*base%p;
       b>>=1; 
     }	
     return ans;
    }
    ll C(ll n,ll m)
    {
      if(n<m) return 0;
      return inv[n]*qpow(inv[n-m],p-2)%p*qpow(inv[m],p-2)%p;	
    }
    ll lucas(ll n,ll m)
    {
      if(n<m) return 0;
      if(n==0) return 1;
      return C(n%p,m%p)*lucas(n/p,m/p)%p;
    } 
    int main()
    {
     scanf("%d",&t);
     while(t--)
     {
      scanf("%lld%lld%lld",&n,&m,&p);
      inv[0]=1;
      for(int i=1;i<=n+m;i++)
      inv[i]=inv[i-1]*i%p;
      printf("%lld
    ",lucas(n+m,m));	
     }
     return 0;	
    }
    

    6.错排问题

    递推公式:(d[i]=(i-1)(d[i-1]+d[i-2])),其中(d[0]=1),(d[1]=0);

    证明:见此博客

    例题:排列计数

    满分作法:相当于在(n)个数中选(m)个数,剩下的错排即可

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    const int maxm=1e6+7;
    const ll mo=1e9+7;
    int t;
    int n,m;
    ll d[maxm];//错排数
    ll inv[maxm];
    ll qpow(ll a,ll b)
    {
      ll ans=1,base=a;
      while(b){
       if(b&1)
       ans=ans*base%mo;
       base=base*base%mo;
       b>>=1;
     }
     return ans;
    }
    ll C(ll n,ll m)
    {
     if(n<m) return 0;
     return inv[n]*qpow(inv[n-m],mo-2)%mo*qpow(inv[m],mo-2)%mo;	
    }
    int main()
    {
     scanf("%d",&t);
     d[0]=1;//要特殊处理d[0] 
     d[1]=0;
     d[2]=1;
     for(int i=3;i<=maxm-7;i++)
     d[i]=(i-1)*(d[i-1]+d[i-2])%mo;
     inv[0]=1;
     for(int i=1;i<=maxm-7;i++)
     inv[i]=inv[i-1]*i%mo;
     while(t--)
     {
      scanf("%d%d",&n,&m);
      printf("%lld
    ",C(n,m)*d[n-m]%mo);
     }
     return 0;	
    }
    

    7.卡特兰数

    1.令(h(0)=1,h(1)=1)(catalan)数满足递推式。(h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (n>=2))

    2.(h(n)=C(2n,n)/(n+1))

  • 相关阅读:
    迭代器
    关于文章cisco漏洞4786
    Python学习目录
    Python的xml模块
    【JS30】Event Capture, Propagation, Bubbling and Once
    mysql安装
    CS193P 第四课笔记 · Hexo
    CSS变量
    在CentOS7上开启和挂载NFS共享
    《Android 编程实战》Chap5_重识IPC
  • 原文地址:https://www.cnblogs.com/lihan123/p/11839716.html
Copyright © 2020-2023  润新知