乘法逆元的定义
1.1 极简定义
在 模m 有意义的条件下, 若 ax ≡ 1 ( mod m ), 则称 a 关于 1 模 m的乘法逆元为 x
1.2 详细定义
若整数 a,m 互质,并且对于任意的整数 b,如果满足 a | b ( a 能整除 b ),则存在一个整数 x,使得 b/a ≡ bx ( mod m ) ,则称 x 为 a 模 m 的乘法逆元,记为 a^(-1) ( mod m ) 或者 inv( a )。
预处理 + 乘法逆元,适用于mod为素数且比较大的时候(超过10^5)
预处理的时候注意: m!的MOD次方 = (m-1)!的MOD次方 * m的MOD次方
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<vector>
#define LL long long
#define maxn 1000000
using namespace std;
const int MOD = 998244353;
LL fact[maxn + 5]; //阶乘
LL a[maxn + 10]; // 乘法逆元
//LL inv[maxn+10]; //快速幂
LL pow(LL x)
{
LL n = MOD - 2;
LL res = 1;
while (n > 0)
{
if (n % 2 == 1)
res = res * x % MOD;
x = x * x % MOD;
n >>= 1;
}
return res;
}
void init() {
a[0] = a[1] = 1;
fact[0] = fact[1] = 1;
// inv[1] = 1;
for (int i = 2; i <= 1000005; i++)
{
fact[i] = fact[i - 1] * i % MOD;
a[i] = a[i - 1] * pow(i) % MOD; //m!的MOD次方 = (m-1)!的MOD次方 * m的MOD次方
// inv[i] = (MOD - MOD/i)*inv[MOD%i]%MOD;
// a[i] = a[i-1] * inv[i] % MOD;
}
}
LL C(int n, int m) { //乘法逆元
if (n < 0 || m < 0 || n < m)return 0;
return fact[n] * a[n - m] % MOD * a[m] % MOD;
}
int main()
{
int T, n, m;
LL ans;
init();//预处理
cin >> T;
while (T--)
{
cin >> n >> m;
ans = C(n, m) % MOD;
printf("%lld\n", ans);
}
return 0;
}
利用n!=2^a1*3^a2*…p^ak(p为质数),将原方程(n+m)!/(n!*m!)化为2^(a1-b1-c1)*3^(a2-b2-c2)…*p^(ak-bk-ck),n!分解后p的次数为:n/p+n/p^2+…+n/p^k,则原式可以化成这k项式子对Mod取余的乘积。
输入样例
5
3 1
3 2
5 2
1086 547
659872 329980
输出样例
3
3
10
677924779
165932997
// 质数化简求C(n+m,m)
#include <iostream>
#include <vector>
using namespace std;
#define Mod 998244353
typedef long long ll;
// 计算n以内所有的质数
vector<int> primelessthanN(int n)
{
vector<bool> isprime(n+1, true);
vector<int> prime;
prime.push_back(2);
int i;
for(i=3; i*i<=n; i+=2)
{
if(isprime[i])
{
prime.push_back(i);
for(int j=i*i; j<=n; j+=i)
isprime[j]=false;
}
}
while(i<=n)
{
if(isprime[i])
prime.push_back(i);
i+=2;
}
return prime;
}
// 计算素数因子p的指数
int Cal(int n, int p)
{
int res=0;
ll rec=p;
while((ll)n>=rec)
{
res+=(int)((ll)n/rec);
rec*=(ll)p;
}
return res;
}
// 计算n^k对Mod取余
ll PowerMod(int n, int k)
{
int t(k),n0(n);
ll res=(ll)1;
while(t)
{
if(t&1)
res=(res*(ll)n0)%Mod;
n0=(n0*n0)%Mod;
t>>=1;
}
return res;
}
// 计算C(n,m),即原式的C(n+m,m)
ll Cnm(int n, int m)
{
vector<int> prime=primelessthanN(n);
ll res=1;
for(int i=0; i<prime.size(); i++)
{
res=(res*(PowerMod(prime[i],Cal(n,prime[i])-Cal(n-m,prime[i])-Cal(m,prime[i]))))%Mod;
}
return res;
}
// main函数
int main()
{
int t;
while(t--)
{
int n,m;
cin >> n >> m;
cout << Cnm(n,m>n-m?m:n-m) << endl;
}
system("pause");
return 0;
}