对于组合数C(n,m),我们求C(n,m)%p,当然给定范围是0<=n,m<=10^6,p<=10^5注意这里p不一定是素数,如果p是素数,很明显,Lucas一下搞定毫
无压力,但是p可能为合数。。。。。。。
对于这个我参照了AC大牛的思路,我们先求出阶乘中各个素因子的幂的次数,这里很巧妙,对于分母的话,就是负次幂,然后直接把每个素因子的幂
次统计在一个数组里面保存,最后就直接二分求问题的解,具体思路参照代码:
- #include <stdio.h>
- #include <string.h>
- typedef long long LL;
- const int N = 2000001;
- const int M = 150000;
- LL MOD;
- bool prime[N];
- LL p[M];
- LL k=0;
- void isprime()
- {
- LL i,j;
- memset(prime,true,sizeof(prime));
- for(i=2;i<N;i++)
- {
- if(prime[i])
- {
- p[k++]=i;
- for(j=i+i;j<N;j+=i)
- {
- prime[j]=false;
- }
- }
- }
- }
- LL multi(LL a, LL b, LL m)
- {
- LL ans=0;
- a%=m;
- while(b)
- {
- if(b&1)
- {
- ans=(ans+a)%m;
- b--;
- }
- b>>=1;
- a=(a+a)%m;
- }
- return ans;
- }
- LL quick_mod(LL a,LL b,LL m)
- {
- LL ans=1;
- a%=m;
- while(b)
- {
- if(b&1)
- {
- ans=ans*a%m;
- b--;
- }
- b>>=1;
- a=a*a%m;
- }
- return ans;
- }
- LL fac(LL n,LL A[],LL d)
- {
- LL i;
- for(i=0;i<k&&p[i]<=n;i++)
- {
- LL x=n;
- while(x)
- {
- A[i]+=d*(x/p[i]);
- x/=p[i];
- }
- }
- return i;
- }
- LL C(LL n,LL m)
- {
- LL temp;
- LL A[M];
- memset(A,0,sizeof(A));
- temp=fac(n,A,1);
- fac(m,A,-1);
- fac(n-m,A,-1);
- LL ret=1;
- for(LL i=0;i<temp;i++)
- ret=multi(ret,quick_mod(p[i],A[i],MOD),MOD);
- return ret%MOD;
- }
- int main()
- {
- isprime();
- LL t,n,m;
- scanf("%I64d",&t);
- while(t--)
- {
- scanf("%I64d%I64d%I64d",&n,&m,&MOD);
- LL ans = C(m+n-2,n-1)%MOD;
- printf("%I64d\n",ans);
- }
- return 0;
- }