题目描述
众所周知,明明很喜欢摸鱼,所以他养了n条各不相同的鱼。
某天,明明想摸一下其中m条鱼,他想知道他有多少种不同的摸鱼方案。
我们认为两种方案不同,当且仅当存在至少一条鱼,在方案一种被摸过,在方案二中没被摸过。
由于答案可能过大,请输出答案取模 998244353 后的数值。
输入格式
在第一行中有一个正整数 t(1≤t≤100),表示测试用例的组数。
随后有 t 行,每行有两个以空格相间隔的正整数 n,m(1≤n≤106,0≤m≤n)。
题目保证每个测试用例中 n 的总和不超过 106。
输出格式
对于每一组 n,m,输出一行,为方案数取模 998244353 后的结果数值。
输入样例
5
3 1
3 2
5 2
1086 547
659872 329980
输出样例
3
3
10
677924779
165932997
- 求取1到n的阶乘对 mod 取模的结果存入数组 JC[] 中;
- 求取 时, 先利用“拓展欧几里得算法”或者“费马小定理+快速幂”求 JC[r]的逆元存入临时变量 ;
- 然后计算 存入临时变量 ;( 即为 的值)
- 求取JC[n - r] 的逆元存入临时变量 ;
- 则可以得到
#include <iostream>
using namespace std;
const long long N=1e6+5;
const long long p=998244353;
long long jc[N];
//注意都要用longlong
void get_jc()
{
jc[0]=jc[1]=1;
for(long long i=2;i<=N-5;i++)
{
jc[i]=jc[i-1]*i %p;
//cout<<jc[i]<<" ";
}
}
long long niyuan(long long a)
{
long long ans=1,tp=p-2;
while(tp)
{
if(tp&1) ans=ans*a%p;
a=a*a%p;
tp>>=1;
//cout<<ans<<"**"<<endl;
}
return (ans+p)%p;
}
int main()
{
int t;
cin>>t;
get_jc();
while(t--)
{
long long n,m;
cin>>n>>m;
cout<<jc[n]<<" "<<niyuan(jc[m])<<" "<<jc[n-m]<<endl;
long long out=jc[n] * niyuan(jc[m]) % p * niyuan(jc[n-m]) % p;
cout<<out<<endl;
}
return 0;
}