概述
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}
C2nn−1 种。
相减,得到Katalan数列的个数。
C
2
n
n
n
+
1
{C^{n}_{2n}}\over{n+1}
n+1C2nn