Lucas

Lucas //求c(n,m)%p 其中p是质数

# include <bits/stdc++.h>
using namespace std;

typedef long long LL;
LL mulit(LL a,LL b,LL mod)
{
   LL res=0;
   while(b){
       if(b&1) res=(res+a)%mod;
       a=(a<<1)%mod;
       b>>=1;
  }
   return res;
}
LL quick_pow(LL a,LL b,LL mod)
{
   LL ret=1;
   while(b){
       if(b&1) ret=mulit(ret,a,mod);
       a=mulit(a,a,mod);
       b>>=1;
  }
   return ret;
}
LL comp(LL a,LL b,LL mod)
{
   if(a<b) return 0;
   if(a==b) return 1;
   if(b>(a-b)) b=a-b;

   LL ans=1,ca=1,cb=1;
   for(int i=0;i<b;i++) ca=ca*(a-i)%mod,cb=cb*(b-i)%mod;
   ans=ca*quick_pow(cb,mod-2,mod)%mod;//ca*inv(cb) 此处是用了费马小定理求逆元,当然也可以用扩展gcd
   return ans;
}
LL lucas(LL a,LL b,LL mod)
{
   if(a<mod&&b<mod) return comp(a,b,mod);
   return comp(a%mod,b%mod,mod)*lucas(a/mod,b/mod,mod)%mod;
}
int main()
{
   int T;
   scanf("%d",&T);

   while(T--){
       LL n,m,p;
       scanf("%lld %lld %lld",&n,&m,&p);

       LL d=lucas(n+m,m,p);
       printf("%lld\n",d);
  }

   return 0;
}

//扩展lucas 求 c(n,m)%p p没有限制

# include <bits/stdc++.h>
using namespace std;

typedef long long LL;
LL mul(LL a,LL b,LL mod)
{
   LL res=0;
   while(b){
       if(b&1LL) res=(res+a)%mod;
       a=(a+a)%mod;
       b>>=1;
  }
   return res;
}
LL quick_pow(LL a,LL b,LL mod)
{
   LL ret=1;
   while(b){
       if(b&1LL) ret=mul(ret,a,mod);
       a=mul(a,a,mod);
       b>>=1;
  }
   return ret;
}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
   if(b==0){ x=1,y=0;return a; }
   LL d=exgcd(b,a%b,x,y);
   LL z=x;x=y;y=z-y*(a/b);
   return d;
}
LL inv(LL a,LL p)
{
   if(!a) return 0LL;
   LL x,y;
   exgcd(a,p,x,y);
   x=(x%p+p)%p;//最小非负x
   return x;
}
LL Mul(LL n,LL pi,LL pk)
{
   if(!n) return 1LL;
   LL ans=1LL;
   for(LL i=2;i<=pk;i++)//以p^t为周期取余是一样的
       if(i%pi) ans=ans*i%pk;
   ans=quick_pow(ans,n/pk,pk);

   for(LL i=2;i<=n%pk;i++)//孤立出来的不超过p^t长度
       if(i%pi) ans=ans*i%pk;

   return ans*Mul(n/pi,pi,pk)%pk;
}
LL exlucas(LL n,LL m,LL p,LL pi,LL pk)//p为题目要求的模数,pi为当前分解出来的质因数,pk为当前分解出来的质因数的指数次幂
{
   if(m>n) return 0LL;
   LL a=Mul(n,pi,pk),b=Mul(m,pi,pk),c=Mul(n-m,pi,pk);

   //计算n!,m!,(n-m)!里面含有多少个p   一个数可能含有多个p,那么取出来就会有好多个p (k个)
   //就是把含有质因子都全部搞出来,因为后面的(n/pi!也会重复之前的过程,然后也会把现有的质因子搞出来。就是每次都只是搞一遍,但是对第二次来说相当于第一次搞了两遍,还不如一次全部都搞出来,每一次就按照上面的(Mul())那个算其他的乘积就可以了
   LL k=0LL,ans=0LL;
   for(LL i=n;i;i/=pi) k+=i/pi;
   for(LL i=m;i;i/=pi) k-=i/pi;
   for(LL i=n-m;i;i/=pi) k-=i/pi;

   ans=a*inv(b,pk)%pk*inv(c,pk)%pk*quick_pow(pi,k,pk)%pk;

   return ans*(p/pk)%p*inv(p/pk,pk)%p;  //中国剩余定理 a[i]*M*x 余数*其他各个素数
}
int main()
{
   LL n,m,p,ans=0;
   while(~scanf("%lld %lld %lld",&n,&m,&p)){
       for(LL x=p,i=2;i<=p;i++){
           if(x%i==0){
               LL pk=1LL;
               while(x%i==0) pk*=i,x/=i;
               ans=(ans+exlucas(n,m,p,i,pk))%p;
          }
      }
       printf("%lld\n",ans);
       ans=0;
  }
   return 0;
}



posted @ 2022-02-26 23:10  fengzlj  阅读(56)  评论(0)    收藏  举报