1.当n,m都很小的时候可以利用杨辉三角直接求。
C(n,m)=C(n-1,m)+C(n-1,m-1);

2、n和m较大,但是p为素数的时候

Lucas定理是用来求 c(n,m) mod p,p为素数的值

C(n,m)%p=C(n/p,m/p)*C(n%p,m%p)%p

也就是Lucas(n,m)%p=Lucas(n/p,m/p)*C(n%p,m%p)%p

求上式的时候,Lucas递归出口为m=0时返回1

求C(n%p, m%p)%p的时候,此处写成C(n, m)%p(p是素数,n和m均小于p)

C(n, m)%p = n! / (m ! * (n - m )!) % p = n! * mod_inverse[m! * (n - m)!, p] % p

由于p是素数,有费马小定理可知,m! * (n - m)! 关于p的逆元就是m! * (n - m)!的p-2次方。

p较小的时候预处理出1-p内所有阶乘%p的值,然后用快速幂求出逆元,就可以求出解。p较大的时候只能逐项求出分母和分子模上p的值,然后通过快速幂求逆元求解。

P较大,不打表:

 ll pow(ll a, ll b, ll m)
{
ll ans = ;
a %= m;
while(b)
{
if(b & )ans = (ans % m) * (a % m) % m;
b /= ;
a = (a % m) * (a % m) % m;
}
ans %= m;
return ans;
}
ll inv(ll x, ll p)//x关于p的逆元,p为素数
{
return pow(x, p - , p);
}
ll C(ll n, ll m, ll p)//组合数C(n, m) % p
{
if(m > n)return ;
ll up = , down = ;//分子分母;
for(int i = n - m + ; i <= n; i++)up = up * i % p;
for(int i = ; i <= m; i++)down = down * i % p;
return up * inv(down, p) % p;
}
ll Lucas(ll n, ll m, ll p)
{
if(m == )return ;
return C(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;
}

P较小,打表:

 const int maxn = 1e5 + ;
ll fac[maxn];//阶乘打表
void init(ll p)//此处的p应该小于1e5,这样Lucas定理才适用
{
fac[] = ;
for(int i = ; i <= p; i++)
fac[i] = fac[i - ] * i % p;
}
ll pow(ll a, ll b, ll m)
{
ll ans = ;
a %= m;
while(b)
{
if(b & )ans = (ans % m) * (a % m) % m;
b /= ;
a = (a % m) * (a % m) % m;
}
ans %= m;
return ans;
}
ll inv(ll x, ll p)//x关于p的逆元,p为素数
{
return pow(x, p - , p);
}
ll C(ll n, ll m, ll p)//组合数C(n, m) % p
{
if(m > n)return ;
return fac[n] * inv(fac[m] * fac[n - m], p) % p;
}
ll Lucas(ll n, ll m, ll p)
{
if(m == )return ;
return C(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;
}

3、n,m较大且p不为素数的时候

扩展Lucas定理:

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + ;
const int mod = 1e9 + ;
ll pow(ll a, ll b, ll m)
{
ll ans = ;
a %= m;
while(b)
{
if(b & )ans = (ans % m) * (a % m) % m;
b /= ;
a = (a % m) * (a % m) % m;
}
ans %= m;
return ans;
}
ll extgcd(ll a, ll b, ll& x, ll& y)
//求解ax+by=gcd(a, b)
//返回值为gcd(a, b)
{
ll d = a;
if(b)
{
d = extgcd(b, a % b, y, x);
y -= (a / b) * x;
}
else x = , y = ;
return d;
}
ll mod_inverse(ll a, ll m)
//求解a关于模上m的逆元
//返回-1表示逆元不存在
{
ll x, y;
ll d = extgcd(a, m, x, y);
return d == ? (m + x % m) % m : -;
} ll Mul(ll n, ll pi, ll pk)//计算n! mod pk的部分值 pk为pi的ki次方
//算出的答案不包括pi的幂的那一部分
{
if(!n)return ;
ll ans = ;
if(n / pk)
{
for(ll i = ; i <= pk; i++) //求出循环节乘积
if(i % pi)ans = ans * i % pk;
ans = pow(ans, n / pk, pk); //循环节次数为n / pk
}
for(ll i = ; i <= n % pk; i++)
if(i % pi)ans = ans * i % pk;
return ans * Mul(n / pi, pi, pk) % pk;//递归求解
} ll C(ll n, ll m, ll p, ll pi, ll pk)//计算组合数C(n, m) mod pk的值 pk为pi的ki次方
{
if(m > n)return ;
ll a = Mul(n, pi, pk), b = Mul(m, pi, pk), c = Mul(n - m, pi, pk);
ll k = , ans;//k为pi的幂值
for(ll i = n; i; i /= pi)k += i / pi;
for(ll i = m; i; i /= pi)k -= i / pi;
for(ll i = n - m; i; i /= pi)k -= i / pi;
ans = a * mod_inverse(b, pk) % pk * mod_inverse(c, pk) % pk * pow(pi, k, pk) % pk;//ans就是n! mod pk的值
ans = ans * (p / pk) % p * mod_inverse(p / pk, pk) % p;//此时用剩余定理合并解
return ans;
} ll Lucas(ll n, ll m, ll p)
{
ll x = p;
ll ans = ;
for(ll i = ; i <= p; i++)
{
if(x % i == )
{
ll pk = ;
while(x % i == )pk *= i, x /= i;
ans = (ans + C(n, m, p, i, pk)) % p;
}
}
return ans;
} int main()
{
ll n, m, p;
while(cin >> n >> m >> p)
{
cout<<Lucas(n, m, p)<<endl;
}
return ;
}

最新文章

  1. js中的事件委托
  2. java.lang.InstantiationException-反射机制
  3. meta标签的理解
  4. Spring之我见
  5. php大力力 [008节]局部表量
  6. 【Android 界面效果41】Matrix 与 ColorMatrix
  7. OC的类的构造方法
  8. cocos2d-x使用DragonBones动画
  9. 【.Net】文件并发(日志处理)--队列--Redis+Log4Net
  10. SQL server 2008无法连接Local服务器的解决办法
  11. linux培训笔记1
  12. 【字母全排列】 poj 1256
  13. C# 爬虫 Jumony html解析
  14. 51Nod 1781 跑的比谁都快
  15. .net找List1和List2的差集
  16. java this关键字的使用
  17. CentOS 6.5安装squashfs-tools
  18. python模块--re模块
  19. C# json反序列化 对象中嵌套数组 (转载)
  20. activity 运行流程

热门文章

  1. WinForm-SuspendLayout、ResumeLayout、PerformLayou——转载
  2. Gauva的安装——入门篇
  3. mybatis问题: There is no getter for property named &#39;equipmentId&#39; in &#39;class java.lang.String&#39;
  4. MySQL 索引知识总结
  5. 手写堆优化dijkstra
  6. 20个网页设计师应该学习的CSS3经典教程实例
  7. 转 VS Code 快捷键大全,没有更全
  8. Android 简单图片浏览器 读取sdcard图片+形成缩略图+Gallery
  9. 谁动了我的Mac ??
  10. 网络爬虫入门(二)模拟提交以及HttpClient修正