zoukankan      html  css  js  c++  java
  • lucas定理(模板题题解)

    题目很简单,很暴力,就是组合数,没有其他的。

    但是直接暴力会炸wow

    我们可以利用Lucas定理来分解字问题。

    Lucas定理:C(n,m)(mod p)=C(n%p,m%p)*C(n/p,m/p)(mod p);

    所以,我们可以把这个题目分解成子问题:

    C(n,m+n)(mod p)=C(n%p,m+n%p)*C(n/p,(m+n)/p);

    而第二个C又可以用Lucas定理求,

    所以可以递归求解了

    当m=0时,Lucas返回1(C(n,0)=1)

    但是,还是要注意:

    这题要逆元!!!

    这题要逆元!!!

    这题要逆元!!!

    因为组合要除法,所以需要逆元。

    还好题目亲切,p一定是质数,所以直接费马小搞定了。

    于是:O(n)处理阶乘,logn处理逆元(卡速米)lognLucas

    所以整体复杂度应该是O(Tnlog^2n )(应该不太对)

    贴代码,有些注意事项在代码里写出来

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=3e5+10;
    long long n,m,p;
    long long ksm(long long a,long long b)
    {
        a%=p;
        long long res=1;
        while(b)
        {
            if(b%2==1)
            res=(res*a)%p;
            a=(a*a)%p;
            b>>=1;
        }
        return res;
    }
    long long fac[maxn];
    long long C(long long a,long long b)
    {
        if(a<b)//坑点,如果总数小于方案数(C(n,m)n<m,也就是选不出来)要跳出
        return 0;
        return (fac[a]*ksm(fac[b],p-2))%p*ksm(fac[a-b],p-2)%p;//逆元乘法,求组合数
    }
    
    long long lucas(long long a,long long b)
    {
        if(b==0)
        return 1;
        return lucas(a/p,b/p)*C(a%p,b%p)%p;//Lucas表达
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%lld%lld%lld",&n,&m,&p);
            fac[0]=1;//阶乘
            for(long long i=1;i<=p;i++)
            {
                fac[i]=(fac[i-1]*i)%p;//阶乘
            }
            printf("%lld
    ",lucas(n+m,n));//跑Lucas
        }
        return 0;
    }

    (完)

  • 相关阅读:
    java基础
    php中的$_REQUEST超全局变量
    update 数据表 set 字段1=字段1+id的sql语句
    青蛙跳台阶的相关问题
    Java语言实现石头剪刀布游戏
    Java语言实现palindrome(回文)
    Java语言实现奇怪的比赛
    Java语言实现随意组合
    Java编辑器IDEA的下载与安装
    Vscode下载与汉化
  • 原文地址:https://www.cnblogs.com/ajmddzp/p/11235146.html
Copyright © 2011-2022 走看看