Saving Beans HDU - 3037(卢卡斯定理)
题意:
他们想知道有多少种方法可以在n树中保存不超过m个bean(它们是相同的)。
现在他们求助于你,你应该给他们答案。 结果可能非常巨大; 你应该输出模p的结果,因为松鼠无法识别大数。
1 <= n,m <= 1000000000,p保证是一个素数
题解:
得到公式为:C(n+m,m)%p
利用卢卡斯定理优化
代码:
代码中有两种求逆元的方式
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n, m, p;
ll Ext_gcd(ll a, ll b, ll &x, ll &y)
{if (b == 0) { x = 1, y = 0; return a; }ll ret = Ext_gcd(b, a%b, y, x);y -= a / b * x;return ret;
}
ll Inv(ll a, int m)
{ ll d, x, y, t = (ll)m;d = Ext_gcd(a, t, x, y);if (d == 1) return (x%t + t) % t;return -1;
}
ll poww(ll a,ll b,ll p){ll ans=1;while(b){if(b&1)ans=(ans*a)%p;a=(a*a)%p;b>>=1;} return ans%p;
}
ll Cm(ll n, ll m, ll p)
{ll a = 1, b = 1;if (m > n) return 0;while (m){a = (a*n) % p;b = (b*m) % p;m--;n--;}
// return (ll)a*Inv(b, p) % p; return (ll)a*poww(b, p-2,p) % p;
}int Lucas(ll n, ll m, ll p)
{if (m == 0) return 1;return (ll)Cm(n%p, m%p, p)*(ll)Lucas(n / p, m / p, p) % p;
}int main()
{int T;cin >> T;while (T--){scanf("%lld%lld%lld", &n, &m, &p);printf("%d\n", Lucas(n + m, m, p));}return 0;
}