一直对逆元的知识半知半解。。。
逆元定义
若在 mod p 意义下,对于一个整数 a ,有 a*x=1(mod p);
那么这个这个整数x即为a的乘法逆元。a也为x的乘法逆元。
充分必要条件:gcd(a,p)=1mod p;即a p互质。
用到的知识点:
费马小定理 :
假如p是质数,且gcd(a,p)=1,那么 a^(p-1)≡1(mod p)。即:假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。
通常情况下,p均为质数,则公约数为1的情况基本都可以保证
由费马小定理得:
b^(p-1)%p=1 则:
b*b^(p-2)%p=1 两边同乘a/b,然后左右式交换得:
a/b=a/bbb^(p-2)%p 化简得:
a/b=a*b^(p-2)%p
此时的结果即为a/b的结果,取模得(a/b)%p;
ll mod; //宏定义一个mod
//快速幂
ll quick_pow(ll a,ll b)
{
ll ans=1;
while(b){
if(b&1) ans=(ans*a)%mod;
b>>=1;
a=(a*a)%mod;
}
return ans;
}
//逆元函数 公式为 (a/b)%mod=(a*b^(mod-2))%mod
ll inv(ll a,ll b)
{
return (a*quick_pow(b,mod-2))%mod;
}
/***
注意事项:逆元函数的使用,a必须能整除b,并且mod为质数
**/
int main()
{
ll a,b;
while(cin>>a>>b>>mod){
cout<<inv(a,b)<<endl;
}
return 0;
}
Lucas定理是用来求 c(n,m) mod p,p为素数的值。
卢卡斯定理的定义
假设我们要求的组合数为 C ( n , m ) ,因为这个数比较大,所以通常求的是 C ( n , m ) mod p。卢卡斯定理本来的定义是:
将 m 和 n 分别在 p 进制下表示出来:
那么一定有:
简单点就是:
C(n, m) % p = C(n / p, m / p) * C(n%p, m%p) % p
代码:
// 需要先预处理出fact[],即阶乘
inline ll C(ll m, ll n, ll p)
{
return m < n ? 0 : fact[m] * inv(fact[n], p) % p * inv(fact[m - n], p) % p;
}
inline ll lucas(ll m, ll n, ll p)
{
return n == 0 ? 1 % p : lucas(m / p, n / p, p) * C(m % p, n % p, p) % p;
}
LL Lucas(LL n, LL m, int p){
return m ? Lucas(n/p, m/p, p) * comb(n%p, m%p, p) % p : 1;
}
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 1e9+7;
//组合数取模模板(p较大时,如p=1e9+7)
ll Pow(ll a,ll b)
{
ll ans=1;
while(b){
if(b&1) ans=(ans*a)%p;
a=(a*a)%p;
b>>=1;
}
return ans;
}
ll C(ll n,ll m)
{
if(m==0) return 1;
if(m>n-m) m=n-m;
ll up=1,down=1;
for(int i=1;i<=m;i++){
up=(up*(n-i+1))%p;
down=(down*i)%p;
}
return up*Pow(down,p-2)%p;
}
/***
目的:输出C(n,m)%mod的值
时间复杂度:O(m)
**/
int main()
{
ll m,n;
while(scanf("%lld%lld",&n,&m)!=EOF){
printf("%lld\n",C(n,m));
}
return 0;
}
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e5;
ll n, m, p, fac[N];
void init()
{
int i;
fac[0] =1;
for(i =1; i <= p; i++)
fac[i] = fac[i-1]*i % p;
}
ll q_pow(ll a, ll b)
{
ll ans =1;
while(b)
{
if(b &1) ans = ans * a % p;
b>>=1;
a = a*a % p;
}
return ans;
}
ll C(ll n, ll m)
{
if(m > n) return 0;
return fac[n]*q_pow(fac[m]*fac[n-m], p-2) % p;
}
ll Lucas(ll n, ll m )
{
if(m ==0) return 1;
else return (C(n%p, m%p)*Lucas(n/p, m/p))%p;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
scanf("%I64d%I64d%I64d", &n, &m, &p);
init();
printf("%I64d\n", Lucas(n, m));
}
return 0;
}