zoukankan      html  css  js  c++  java
  • 组合数取模学习笔记

    组合数取模的话,之前多少会一些,能应付一般的题目,而这次遇到了模数为合数的题目,于是就又来学习了一发.
    这次看到了一个比较不错的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
    ",ans);
      return 0;
    }
  • 相关阅读:
    中国黑客传说:游走在黑暗中的精灵
    智能硬件安全入门
    迈克菲:2016年的八大网络安全威胁
    走进科学之WAF(Web Appllication Firewall)篇
    从对SAE的一次授权安全评估浅谈云安全
    沟通的艺术,心理学与生活,学会提问
    知道创宇研发技能表v3.0
    SYN Cookie的原理和实现
    1043. 输出PATest(20)
    1042. 字符统计(20)
  • 原文地址:https://www.cnblogs.com/TSHugh/p/8638050.html
Copyright © 2011-2022 走看看