概述


AcWing211. 计算系数

#include <bits/stdc++.h>
using namespace std;
const int mod = 10007 ;
int ksm(int a, int b, int p)
{
   
    int ans = 1%p;
    a = a%p;
    while(b)
    {
   
        if(b&1) ans = (long long)ans * a % p;
        a = (long long)a*a%p;
        b>>=1;
    }
    return ans;
}
int jie(int n)
{
   
    int ans = 1;
    for(int i = 1; i <= n; i++)
    {
   
        ans = (long long)ans * i %mod;
    }
    return ans;
}
int niyuan(int x)
{
   
    return ksm(x, mod-2, mod);
}

int main()
{
   
    int a,b,k,n,m;
    cin >> a >> b >> k >> n >> m;
    int fenzi = jie(k);
    int fenmu = jie(k-m)*jie(m) % mod;
    int CC = fenzi * niyuan(fenmu)%mod;
    int asn = ksm(a, n, mod)*ksm(b, m, mod)%mod*CC%mod;
    printf("%d", asn);
    return 0;
}

多重集

AcWing212. 计数交换


Lucas定理

古代猪文

先对合数进行分解的代码:

#include <bits/stdc++.h>
using namespace std;
int main()
{
   
    int x = 999911658;
    for(int i = 2; (long long)i*i <= x; i++)
    {
   
        if(x % i==0)
        {
   
            printf("%d\t", i);
            int cnt = 0;
            while(x%i==0)
            {
   
                x /= i;
                cnt ++;
            }
            printf("%d\n", cnt);
        }
    }
    if(x > 1)
    printf("%d\t1\n", x);
    return 0;
}

运行结果

2	1
3	1
4679	1
35617	1

Catalan定理

证明如下:
证明要点:

  • 从反方向来进行考虑
  • 把一个不好计数的集合与一个已知的可计数的集合建立一一映射

容易得到:
总共有 C 2 n n C^n_{2n} C2nn 种情况。
现在思考不成立的情况:
建立映射:

P(不合法情况集合) Q(有n-1个0,n+1个1)
找到一个最短的前缀,不满足条件。(这个前缀里面有1的个数比0的个数多1) 然后把其他部分取反,得到q 同左,找到最短的前缀,使得前缀里面有1的个数比0的个数多1 然后把后面取反

容易证明:
已知一个不合法的原情况,可以映射到Q。
而在Q中,也可以映射到P。
说明两个集合相互包含,进而得到两个集合相等。
故个数相等。
所以不合法的情况有 C 2 n n − 1 C^{n-1}_{2n} C2nn1 种。
相减,得到Katalan数列的个数。
C 2 n n n + 1 {C^{n}_{2n}}\over{n+1} n+1C2nn