zoukankan      html  css  js  c++  java
  • 组合数取模

    1.n,m<=1000 p随意

       暴力

    2.n,m<=10^6  p<=10^9 素数合数无影响

       分解质因数,然后快速幂 

       如果p是素数,且多次询问可以预处理阶乘的模以及阶乘的逆元

    3.n,m<=10^9  p<=10^5且是质数

       lucas定理  多次询问也可以预处理

    4.n,m<=10^9  p<=10^5且是合数

       目前还不会做系列。。。

       我们把p拆成 pi^ci 然后对每个pi求模,最后CRT(中国剩余定理)合并一下。

       考虑如何求这个。

       其实我们只要考虑n!mod p^c即可

       然后我们发现:

        n! = [ 1 * 2 * 4 * 5 * 7 * 8 * …  * 16 * 17 * 19 ] * (3 * 6 * 9 * 12 * 15 * 18)= [ 1 * 2 * 4 * 5 * 7 * 8 * …  * 16 * 17* 19 ] * 3^6( 1 * 2 * 3 * 4 * 5 * 6)

        把p单独处理之后发现前面是以p^c为周期的(显然),然后后面划归成了n/p,可以递归求解。然后p的次数就是n/p。

        这样我们就可以预处理阶乘,将是p的倍数的位数省略,以1代过。最后p快速幂一下就好。在分子上的话其实一样,只需要预处理成阶乘的逆元即可。

       说起来很麻烦,还是看代码比较好。。。

    void divide(int n)
    {
        for(int i=2;i*i<=n;i++)if(n%i==0)
        {
            p[++cnt]=i;pc[cnt]=1;
            while(n%i==0)pc[cnt]*=i,n/=i;
        }
        if(n>1)p[++cnt]=n,pc[cnt]=n;
    }
    inline ll power(ll x,ll y,ll p)
    {
        ll t=1;
        for(;y;y>>=1,x=x*x%p)
            if(y&1)t=t*x%p;
        return t;
    }
    inline void exgcd(ll a,ll b,ll &x,ll &y)
    {
        if(!b){x=1;y=0;return;}
        exgcd(b,a%b,x,y);
        ll t=x;x=y,y=t-a/b*y;
    }
    inline ll inv(ll a,ll b)
    {
        ll x,y;
        exgcd(a,b,x,y);
        return (x%b+b)%b;
    }
    inline ll calc(ll n,ll p,ll pc)
    {
        if(n<p)return fac[n];
        now+=n/p;
        return fac[n%pc]*power(fac[pc-1],n/pc,pc)%pc*calc(n/p,p,pc)%pc;
    }
    inline ll solve(ll p,ll pc)
    {
        fac[0]=1;
        for1(i,pc-1)fac[i]=fac[i-1]*(i%p?i:1)%pc;
        now=0;
        ll t1=calc(n,p,pc),t2=1,cx=now,cy;
        for1(i,pc-1)fac[i]=fac[i-1]*(i%p?inv(i,pc):1)%pc;
        now=0;
        for1(i,m)t2=t2*calc(v[i],p,pc)%pc;
        cy=now;
        return t1*t2%pc*power(p,cx-cy,pc)%pc;
    }    
    
    int main()
    
    {
    
        freopen("input.txt","r",stdin);
    
        freopen("output.txt","w",stdout);
    
        mod=read();n=read();m=read();
        for1(i,m)v[i]=read(),sum+=v[i];
        if(sum>n){printf("Impossible
    ");return 0;}
        if(sum<n)v[++m]=n-sum;
        divide(mod);
        ll ans=0;
        for1(i,cnt)
         {
             ll t1=solve(p[i],pc[i]),t2=inv(mod/pc[i],pc[i]);
             (ans+=t1*t2%mod*(mod/pc[i])%mod)%=mod;
         }
        cout<<(ans+mod)%mod<<endl;
    
        return 0;
    
    }  

    5.n,m<=10^9  p<=10^9

       目前无解决方法貌似?当然你要是和我说 pi^ci<=10^5 我就呵呵了。。。

      

  • 相关阅读:
    【阿里云IoT+YF3300】6.物联网设备报警配置
    【阿里云IoT+YF3300】5. Alink物模型之服务下发
    【阿里云IoT+YF3300】4.Alink物模型之事件触发
    【阿里云IoT+YF3300】3. Alink物模型之属性上传和下发
    腾讯物联TencentOS tiny上云初探
    【阿里云IoT+YF3300】2.阿里云IoT云端通信Alink协议介绍
    【阿里云IoT+YF3300】1.时代大背景下的阿里云IoT物联网的现状和未来
    阿里云的物联网之路
    阿里云智能接入网关体验
    imx:MfgTool
  • 原文地址:https://www.cnblogs.com/zyfzyf/p/4201833.html
Copyright © 2011-2022 走看看