組合數取模學習筆記

組合數取模的話,以前多少會一些,能應付通常的題目,而此次遇到了模數爲合數的題目,因而就又來學習了一發.
此次看到了一個比較不錯的blog:https://blog.csdn.net/skywalkert/article/details/52553048
在這個blog裏,其1.3裏的內容,有許多不理解的地方,而且3.2及之後的內容,並無去研究.
此次主要是get到了用crt解決模數爲合數的問題,而且還有與其配套使用的模數爲質數的冪的問題.
複習了一下crt,crt就是去按照一個正確且比較方便的方法去構造一個解,而且利用了數在模裏模外意義不一樣.
下面給出解決此類問題的代碼以及代碼註釋:
(此代碼對應於具體題目,請讀者抓住重點)函數

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=1000010;
int n,x,y,mod,P,p,phi,fac[N],num;
inline int Pow(int x,int y){
  int ret=1;
  while(y){
    if(y&1)ret=(LL)ret*x%P;
    x=(LL)x*x%P,y>>=1;
  }
  return ret;
}
inline int cnt(int n){
  return n?n/p+cnt(n/p):0;
  //遞歸處理n的階乘裏p的個數
}
inline int sum(int n){
  return n?((LL)(n/P?Pow(fac[P],n/P):1)*fac[n%P]%P*sum(n/p)%P):1;
  //遞歸處理n的階乘裏刨去p以後,在模P的意義下的結果
  //爲何要遞歸呢?
  //咱們發現,咱們預處理的時候,若是預處理的是刨去p的,那麼他根本不循環.
  //由於對於一個含有p的數來講,他刨去p,和他加上P以後再刨去p,是不同的.
  //因此說,咱們要預處理的是不含p的數的階乘,也就是說,若是一個數含有p,那就不乘他.
  //那麼咱們首先處理的是不含p的,而後去遞歸含有一個p的,而後是兩個的……
  //這樣答案就對了.
  //這樣好騷啊,一開始因爲不知道這個操做而錯*N……
  //不過這玩意log^2的吧……
}
//以上兩個函數每次都尼瑪能夠在一開始處理階乘的時候處理出來……而後就會跑得飛快……
//不過預處理的話,必需要求n較小,可是遞歸的話,只要n或P中的一個很小就能夠了.
#define deal(n,a,b) int a=sum(n),b=cnt(n);
inline int C(int n,int m){
  if(m>n)return 0;
  deal(n,a0,b0)
  deal(m,a1,b1)
  deal(n-m,a2,b2)
  b0-=b1+b2;
  if(b0>=num)return 0;
  return (LL)a0*Pow(a1,phi-1)%P*Pow(a2,phi-1)%P*Pow(p,b0)%P;
}
inline int calc(){
  int ret=0,i,a,b,c,d;
  fac[0]=1;
  for(i=1;i<=P&&i<=n;++i)
    fac[i]=(i%p)?(LL)fac[i-1]*i%P:fac[i-1];
  a=0,b=x,c=(n-y-x)>>1,d=(n+y-x)>>1;
  while(c>=0){
    ret=(ret+(LL)C(n,a+b)*C(a+b,a)%P*C(c+d,c)%P)%P;
    ++a,++b,--c,--d;
  }
  return ret;
}
int main(){
  //freopen("rio.in","r",stdin);
  scanf("%d%d%d%d",&n,&mod,&x,&y);
  x=std::abs(x),y=std::abs(y);
  if(n-y-x<0||((x&1)!=((n+y)&1))){
    puts("0");
    return 0;
  }
  int i,s=mod,ans=0;
  for(i=2;s>1;++i){
    if(i*i>s)i=s;
    if(s%i==0){
      p=i,P=1,num=0;
      while(s%p==0)
        ++num,P*=p,s/=p;
      phi=P/p*(p-1);
      ans=(ans+(LL)calc()*(mod/P)%mod*Pow(mod/P,phi-1))%mod;
    }
  }
  printf("%d\n",ans);
  return 0;
}
相關文章
相關標籤/搜索