组合数&杨辉三角&卢卡斯定理&费马小定理
用于快速计算出组合数
1.组合数的计算——杨辉三角
题目:P1313 [NOIP2011 提高组] 计算系数 P2822 [NOIP2016 提高组] 组合数问题
#include<bits/stdc++.h>
using namespace std;
int k,n,m,f[2010][2010];
int main()
{
scanf("%d%d%d",&k,&n,&m);
for(int i=0;i<=k;i++)
{
f[i][0]=1;
for(int j=1;j<=i;j++)
{
f[i][j]=f[i-1][j-1]+f[i-1][j];
}
}
printf("%d",f[n][m]);
return 0;
}
2.组合数的计算——卢卡斯定理&费马小定理
卢卡斯定理:C(n,m)%p=C(n%p,m%p)*C(n/p,m/p)%p
卢卡斯定理可用于计算组合数(快速计算)。
费马小定理:a^(p-1)%p=1 ---> a^(p-2)%p=1/a 【条件:p是质数且p与a互质】
费马小定理可支持在做除法时取模(把除法转为乘法)。
题目:P3807 【模板】卢卡斯定理/Lucas 定理
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll a[100010];
int t,n,m,p;
ll pow(ll y,int z,int p)
{
y%=p;ll ans=1;
for(int i=z;i;i>>=1,y=y*y%p)if(i&1)ans=ans*y%p;
return ans;
}
ll C(ll n,ll m)
{
if(m>n)return 0;
return ((a[n]*pow(a[m],p-2,p))%p*pow(a[n-m],p-2,p)%p);
//a^(p-1)%p=1 费马小定理
}
ll Lucas(ll n,ll m)
{
if(!m)return 1;
return C(n%p,m%p)*Lucas(n/p,m/p)%p;
//C(n,m)%p=C(n%p,m%p)*C(n/p,m/p)%p 卢卡斯定理
}
int main(){
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&p);
a[0]=1;
for(int i=1;i<=p;i++) a[i]=(a[i-1]*i)%p;
printf("%lld\n",Lucas(n+m,n));
}
return 0;
}
3.组合数的奇葩性质
①:C(n,1)+C(n,2)+C(n,3)+...+C(n,n)=2^(n-1)
题目:P3414 SAC#1 - 组合数
②:如果在C(n,k)中,(n&k)==k,则C(n,k)的结果为奇数