Time Limit: 2 second(s) | Memory Limit: 32 MB |
Given n different objects, you want to take k of them. How many ways to can do it?
For example, say there are 4 items; you want to take 2 of them. So, you can do it 6 ways.
Take 1, 2
Take 1, 3
Take 1, 4
Take 2, 3
Take 2, 4
Take 3, 4
Input
Input starts with an integer T (≤ 2000), denoting the number of test cases.
Each test case contains two integers n (1 ≤ n ≤ 106), k (0 ≤ k ≤ n).
Output
For each case, output the case number and the desired value. Since the result can be very large, you have to print the result modulo 1000003.
Sample Input | Output for Sample Input |
3 4 2 5 0 6 4 | Case 1: 6 Case 2: 1 Case 3: 15 |
定义:对于正整数和,如果有,那么把这个同余方程中的最小正整数解叫做模的逆元。逆元一般用扩展欧几里得算法来求得,如果为素数,那么还可以根据费马小定理得到逆元为
推导过程如下
给你们我师父关于这个Lucas定理的总结,不说了,我去偷学了。点击打开师父总结
这个是用费马小定理直接写的:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;
#define CLR(a,b) memset(a,b,sizeof(a))
#define M 1000003
#define LL long long
LL pr[M+10];
LL poww[M+10];
void init1()
{
pr[0]=1;
for(int i=1;i<M;i++) //求n的阶乘
pr[i]=pr[i-1]*i%M;
}
LL quick(LL n,LL m,LL k) //(n^m)%k
{
LL ans=1;
while(m)
{
if(m&1)
ans=ans*n%k;
n=(n*n)%k;
m>>=1;
}
return ans;
}
void init2() //求 m 的阶乘和 n-m 阶乘的逆元
{
poww[0]=1;
poww[1]=1;
for(LL i=2;i<M;i++)
poww[i]=quick(pr[i],M-2,M); //用快速幂求逆元
}
int main()
{
int u,ca=1;
init1();
init2(); //放里面当然会超时啦,每次都要算啊
scanf("%d",&u);
while(u--)
{
LL n,m,a,b,c,ans;
scanf("%lld %lld",&n,&m);
a=pr[n];
b=poww[m];
c=poww[n-m];
ans=(a*b%M)*c%M;
printf("Case %d: %lld\n",ca++,ans);
}
return 0;
}
Lucas 定理:A、B是非负整数,p是质数。AB写成p进制:A=a[n]a[n-1]...a[0],B=b[n]b[n-1]...b[0] 这里的每一个数组元素表示其p进制的每一位。
则组合数C(A,B)与C(a[n],b[n])*C(a[n-1],b[n-1])*...*C(a[0],b[0])。也就是说,把大组合数问题变成了一个个的小组合数。(A,B小于mod)
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define CLR(a,b) memset(a,b,sizeof(a))
#define M 1000000
#define inf 0x3f3f3f3f
#define LL long long
const LL mod=1000003;
LL fac[M+10]={1,1}; //我好方,居然定义成int了 QAQ
void getfac() //求阶乘
{
for(int i=2;i<=M;i++)
fac[i]=fac[i-1]*i%mod;
}
LL quick_mod(LL n,LL m) //快速幂求逆元
{
LL ans=1;
n%=mod;
while(m)
{
if(m&1)
ans=ans*n%mod;
n=n*n%mod;
m>>=1;
}
return ans;
}
LL C(LL n,LL m)
{
if(m>n)
return 0;
return fac[n]*(quick_mod(fac[m]*fac[n-m]%mod,mod-2))%mod; //还是求C(n,m),同样用逆元求
}
LL Lucas(LL n,LL m)
{
if(m==0)
return 1;
else //分解为mod进制:c(a[i],b[i])*.....
return C( n%mod , m%mod )*Lucas( n/mod , m/mod )%mod;
}
int main()
{
getfac();
int u,ca=1;
scanf("%d",&u);
while(u--)
{
LL n,m;
scanf("%lld %lld",&n,&m);
printf("Case %d: %lld\n",ca++,Lucas(n,m));
}
return 0;
}