zoukankan      html  css  js  c++  java
  • acm数论之旅--组合数(转载)

    ACM数论之旅8---组合数(组合大法好(,,• ₃ •,,) )

    一道组合数与全错排的公式。

    组合数并不陌生(´・ω・`)

    组合数1

    组合数4

    我们都学过组合数

    会求组合数吗

    一般我们用杨辉三角性质

    杨辉三角上的每一个数字都等于它的左上方和右上方的和(除了边界)

    组合数2

    第n行,第m个就是,就是C(n, m) (从0开始)

    电脑上我们就开一个数组保存,像这样

    组合数3

    用递推求

    复制代码
     1 #include<cstdio>
     2 const int N = 2000 + 5;
     3 const int MOD = (int)1e9 + 7;
     4 int comb[N][N];//comb[n][m]就是C(n,m)
     5 void init(){
     6     for(int i = 0; i < N; i ++){
     7         comb[i][0] = comb[i][i] = 1;
     8         for(int j = 1; j < i; j ++){
     9             comb[i][j] = comb[i-1][j] + comb[i-1][j-1];
    10             comb[i][j] %= MOD;
    11         }
    12     }
    13 }
    14 int main(){
    15     init();
    16 }
    复制代码

    https://ac.nowcoder.com/acm/contest/881#question E题,另外一种求组合数。

    #include<bits/stdc++.h>
    #define ll long long
    #define M (ll)(1e9+7)
    using namespace std;
    ll CM[4001]={1};
    ll Pow(ll a,ll b){  //快速幂
        a%=M;
        ll ans = 1;
        for(;b;b>>=1)
        {
            if(b&1) ans = (ans*a)%M;
            a = (a*a)%M;
        }
        return ans;
    }
    ll Quk(ll a,ll b){ //快速乘
        a%=M;
        ll ans = 0;
        for(;b;b>>=1)
        {
            if(b&1) ans = (ans+a)%M;
            a = (a+a)%M;
        }
        return ans;
    }
    ll C(ll m,ll n){ //n>=m
        return Quk(Quk(CM[n],Pow(CM[n-m],M-2)),Pow(CM[m],M-2))%M;
    }
    ll A(ll m,ll n){ //n>=m
        return Quk(CM[n],Pow(CM[n-m],M-2))%M;
    }
    int main()
    {
        ll a,b;
        for(int i=1;i<4001;i++) CM[i]=Quk(CM[i-1],i);
        while(cin>>a>>b)
        {
            ll ans=C(a+b,2*(a+b));
            if(a) ans-=C(a-1,2*(a+b));
            if(b) ans-=C(b-1,2*(a+b));
            cout<<(ans+2*M)%M<<endl;
        }
        return 0;
    }

     需要mod是质数

    #include<bits/stdc++.h>
    using namespace std;
    #define INF 0x3fffffff
    #define maxn 100005
    typedef long long ll;
    ll n,m,k,t;
    const ll mod = 1e9+7;
    ll fac[maxn];
    ll inv[maxn];
    ll qpow(ll a, ll b)
    {
        ll r = 1, t = a;
        while (b) {
            if (b & 1)r = (r*t) % mod;
            b >>= 1;t = (t*t) % mod;
        }
        return r;
    }
    void init()
    {
        fac[0] = 1;
        for (int i = 1;i <= mmax;i++) fac[i] = fac[i - 1] * 1ll * i%mod;
        inv[mmax] = qpow(fac[mmax], mod - 2);
        for (int i = mmax - 1;~i;i--) inv[i] = inv[i + 1] * 1ll * (i + 1) % mod;
    }
    ll C(ll n, ll m)
    {
        if (m>n) return 0;
        if (m == n || m == 0) return 1;
        return fac[n] * 1ll * inv[n - m] % mod*inv[m] % mod;
    }
    int main(){
        init();
        while(~scanf("%lld%lld",&n,&m))
            printf("%lld
    ",(C(2*m+2*n,n+m)+mod-(C(2*m+2*n,n-1)+C(2*m+2*n,m-1))%mod)%mod);
    }

    (PS:大部分题目都要求求余,而且大部分都是对1e9+7这个数求余)

    这种方法的复杂度是O(n^2),有没有O(n)的做法,当然有(´・ω・`)

    因为大部分题都有求余,所以我们大可利用逆元的原理(没求余的题目,其实你也可以把MOD自己开的大一点,这样一样可以用逆元做)

    根据这个公式

    组合数1

    我们需要求阶乘和逆元阶乘

     我们就用1e9+7来求余吧

    long long F[100010];
    void init(long long p)
    {
        F[0] = 1;
        for(int i = 1;i <= p;i++)
            F[i] = F[i-1]*i % (1000000007);
    }
    long long inv(long long a,long long m)
    {
        if(a == 1)return 1;
        return inv(m%a,m)*(m-m/a)%m;
    }
    long long Lucas(long long n,long long m,long long p)
    {
        long long ans = 1;
        while(n&&m)
        {
            long long a = n%p;
            long long b = m%p;
            if(a < b)return 0;
            ans = ans*F[a]%p*inv(F[b]*F[a-b]%p,p)%p;
            n /= p;
            m /= p;
        }
        return ans;
    }

    代码如下:

    复制代码
     1 #include<cstdio>
     2 const int N = 200000 + 5;
     3 const int MOD = (int)1e9 + 7;
     4 int F[N], Finv[N], inv[N];//F是阶乘,Finv是逆元的阶乘 
     5 void init(){
     6     inv[1] = 1;
     7     for(int i = 2; i < N; i ++){
     8         inv[i] = (MOD - MOD / i) * 1ll * inv[MOD % i] % MOD;
     9     }
    10     F[0] = Finv[0] = 1;
    11     for(int i = 1; i < N; i ++){
    12         F[i] = F[i-1] * 1ll * i % MOD;
    13         Finv[i] = Finv[i-1] * 1ll * inv[i] % MOD;
    14     }
    15 }
    16 int comb(int n, int m){//comb(n, m)就是C(n, m) 
    17     if(m < 0 || m > n) return 0;
    18     return F[n] * 1ll * Finv[n - m] % MOD * Finv[m] % MOD;
    19 }
    20 int main(){
    21     init();
    22 }
    复制代码
     
  • 相关阅读:
    二进制数组
    model模块
    Decorator [ˈdekəreɪtə(r)] 修饰器/装饰器 -- 装饰模式
    箭头函数
    async [ə'zɪŋk] 函数
    cocos2d-x 事件分发机制 ——触摸事件监听
    算法:高速排序
    [zlib]_[0基础]_[使用Zlib完整解压zip内容]
    设计模式之状态模式(State)摘录
    编写Web Serviceclient訪问www.webxml.com.cn提供的服务
  • 原文地址:https://www.cnblogs.com/downrainsun/p/9791195.html
Copyright © 2011-2022 走看看