卡特兰数现在我能接触到的用处就是用于解决一个序列中,任意前缀和中1的数量不少于0的数量(在这个序列中,1与0的个数相等)
证明如下图:
卡特兰数 =(公式一) C(2* n , n) - C(2n , n- 1) = (公式二)C(2n , n) / (n + 1)
组合数的板子很多,我们这里简单说3个吧
模板一 :组合数求余大质数
求C(a,b)
时间复杂度: O(a * loga)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 2015;
int n,mod = 1e9 + 7;
int fact[N],infact[N];
int qmi(int a, int k)
{
int res = 1;
while (k)
{
if (k & 1) res = (ll)res * a % mod;
a = (ll)a * a % mod;
k >>= 1;
}
return res;
}
int main()
{
int t,a,b,temp,res;
infact[0] = fact[0] = 1;
for(int i = 1; i < N; i ++)//打表阶乘求余和阶乘的逆元
{
fact[i] = (ll) fact[i - 1] * i % mod;
infact[i] = (ll) infact[i - 1] * qmi(i , mod - 2) % mod;
}
cin >> t;
while(t --)
{
scanf("%d %d",&a,&b);
cout << (ll) fact[a] * infact[b] % mod * infact[a - b] % mod << endl;
}
return 0;
}
模板二:组合数对任意素数求余p (p 不定)
时间复杂度:O(n * logn)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 2e6 + 15;
typedef long long ll;
ll primes[N],cnt;
bool book[N];
ll n,mod;
void get_primes()
{
for(int i = 2; i < N; i ++)
{
if(!book[i]) primes[cnt ++] = i;
for(int j = 0; j < cnt && primes[j] * i < N; j ++)
{
book[primes[j] * i] = true;
if(i % primes[j] == 0) break;
}
}
}
ll get(ll x,ll p)
{
ll res = 0;
while(x)
{
res += x / p;
x /= p;
}
return res;
}
ll qmi(ll a, ll b)
{
ll ans = 1;
a = a % mod;
while(b)
{
if(b % 2 == 1) ans = (ll)ans * a % mod;
a = (ll)a * a % mod;
b /= 2;
}
return ans;
}
ll C(ll a, ll b)
{
ll p,t;
ll res = 1;
for(int i = 0; i < cnt; i ++)
{
p = primes[i];
t = (ll)get(a,p) - get(b,p) - get(a-b,p);
res = (ll) res * qmi(p,t) % mod;
}
return res;
}
int main()
{
get_primes();
scanf("%lld %lld",&n,&mod);
ll a = 2*n,b = n,c = n-1;
cout << ( C(a , b) - C(a , c) + mod) % mod << endl;
return 0;
}
模板三:超大(1e18)组合数求余p(p为质数)
Lucas定理:C(a,b) = C(a % p, b % p) * C(a / p, b / p);
时间复杂度:接近logpN * logp
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int p;
int qmi(int a,int b)
{
int cnt = 1;
a %= p;
while(b)
{
if(b & 1) cnt = (ll) cnt * a % p;
a = (ll)a * a % p;
b /= 2;
}
return cnt;
}
int C(int a, int b)
{
int res = 1;
int temp = min(a - b,b);
for(int i = a, j = temp; j > 0; i -- ,j --)
{
res = (ll) res * i % p;
res = (ll) res * qmi(j , p - 2) % p;
}
return res;
}
int Lucas(ll a,ll b)
{
if(a < p && b < p) return C(a , b);
else return (ll)C(a % p, b % p) * Lucas(a / p, b / p) % p;
}
int main()
{
int t;
cin >> t;
ll a,b;
while(t --)
{
scanf("%lld %lld %d",&a,&b,&p);
cout << Lucas(a,b) % p<< endl;
}
return 0;
}