bzoj 2982: combination lucas定理+乘法逆元

来源:互联网 发布:php linux 删除文件夹 编辑:程序博客网 时间:2024/06/05 11:08

Description

LMZn个不同的基友,他每天晚上要选m个进行[河蟹],而且要求每天晚上的选择都不一样。那么LMZ能够持续多少个这样的夜晚呢?当然,LMZ的一年有10007天,所以他想知道答案mod 10007的值。(1<=m<=n<=200,000,000)

Input

  第一行一个整数t,表示有t组数据。(t<=200)
  接下来t行每行两个整数n, m,如题意。

Output

T行,每行一个数,为C(n, m) mod 10007的答案。

Sample Input

4
5 1
5 2
7 3
4 2

Sample Output

5
10
35
6

分析:一开始以为是傻逼题,一看,woc n<=200000000,然后上网查发现了一个叫lucas定理的神奇的东东。

具体内容就是C(n,m)=C(n%p,m%p)*C(n/p,m/p)

但证明看不太懂,于是这个坑就留着以后再补吧……

那么这题只要用lucas定理然后逆元搞一下就好咯


代码:

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define MOD 10007using namespace std;int f[MOD],ny[MOD];int ksm(int x,int y){if (!y) return 1;if (y==1) return x;int s=ksm(x,y/2);s=s*s%MOD;if (y%2==1) s=s*x%MOD;return s;}int lucas(int n,int m){int ans=1;while (n&&m){int a=n%MOD,b=m%MOD;if (a<b) return 0;ans=ans*f[a]%MOD*ny[b]%MOD*ny[a-b]%MOD;n/=MOD;m/=MOD;}return ans;}int main(){int t;scanf("%d",&t);f[0]=ny[0]=f[1]=ny[1]=1;for (int i=2;i<MOD;i++){f[i]=f[i-1]*i%MOD;ny[i]=ksm(f[i],MOD-2);}while (t--){int n,m;scanf("%d%d",&n,&m);printf("%d\n",lucas(n,m));}return 0;}



0 0