zoukankan      html  css  js  c++  java
  • visit:组合数学,ex_Lucas

    没做过ex_Lucas的同学可以先看看这个:组合数学专题《礼物》题解。顺便把那道题水了。

    强烈推荐tdcp的解,只用求2个组合数,考场打表,没有为什么:666

    有一个公式蛮重要的,竟然还有人不知道?

    有一共n种共k个物品,每一种有a1,a2,a3...an个,它们本质不同的排列数是

    $ frac{k!}{a_1 ! imes a_2 ! imes a_3 ! imes ... imes a_n !}  (sumlimits_{i=1}^n a_i =k) $

    要解释嘛?解释一下吧。

    首先对所有物品进行全排列,k!

    而对于每一种物品,把它从这k个里提出来,其内部的顺序被重复计算了

    所以要除掉它内部的全排列,即ai!。

    那么接下来我们来看着道题。

    首先,我们可以发现,nm的正负对解题没有影响,统一把它当作正的就好(向右,上为正方向)

    那么如果我们一共向左走了a步,那么必须向右走n+a步,同理向下b步就要向上m+b步.(a,b,n-a,m-b均为自然数)

    t=(a)+(n+a)+(b)+(m+b)=n+m+2a+2b

    t-n-m=2a+2b=2(a+b)

    所以说,如果t-n-m为奇数或负数,方案数为0。

    在这个式子里面我们未知的只有a和b。枚举其一就能得到另一个。

    假如我们现在已经确定了一对a,b,如何求解方案数?

    我们有a左(n+a)右b下(m+b)上,我们现在要求这些操作的排列数。

    根据我开头说的那个式子,就挺好写出算式了:(开头那个式子记住吧,挺重要的)

    $ frac{t !}{a ! imes b! imes (n+a)! imes (m+b)!} $

    接下来的问题是如何计算。。。

    对于60%的数据,p是一个质数,简单啊,直接Lucas或阶乘逆元硬干就好了啊

    (如果你连朴素Lucas都不知道,那我救不了你了)

    但是对于全部数据,p可以是一个合数。。。就是礼物那道题了。

    分解p得到若干质数,对于这些质数取模分别求解。

    在求解对于某一个分解后的质数取模时,套一个朴素Lucas即可。

    最后一个CRT合并答案。

    ---接下来你可以选择不看---

    然而我打的十分麻烦。。。我并没有发现需要ex_Lucas和普通Lucas。我以为直接CRT就可以。

    然而40分。懵了一阵。

    仔细一看发现,因为它有小质数所以会爆炸。

    如果要计算$1 imes 3 div 3 (mod 3)$,那么我会先算1×3=3,取模变成0,在除以3还是0。

    呃。。。什么玩意啊!

    后来一想,它不就像ex_Lucas一样吗?只要分离记录那个质数的次数不就好了吗?

    然后我就暴力计算指数的次数,暴力算阶乘。

    那么在上式枚举的过程中,a每增大1,组合数怎么计算?

    我很“机智”的想到了,这不和划艇那题的组合数递推挺像吗?(错误的“做题长记性”)

    既然a是枚举的,每当a增大1,那个式子只需要除a再除n+a再乘b+1再乘m+b+1不就好了吗?

    乘除不能直接乘除,要把分解后的质数提出来。完事!

    完美。

    完美?

    对,对,对是对了,运行倒数第二,码长也十分惊人。

    但是因为没有预处理阶乘和逆元,少开了不少数组,内存492k倒是最小的。

    思维量挺大,理论上是好事,可是在考场上。。。

    不建议按我这个思路打,但是你们可以顺着我的思路想一想,万一用上了呢?

    好了,就这样吧,有什么不懂的去评论区喷我就行,看到就回复。

    这题讲的有点草率,因为要去写T3的题解。

    哦对了,还有,因为我的思路清奇,所以代码还是去颓别人的吧。

     1 #include<cstdio>
     2 #define int long long
     3 #define orz mod[modi]
     4 int Mod,mod[11],mods,t,n,m,ans[11],Ans,x,y;
     5 int pow(int b,int mod,int ans=1){
     6     for(int t=mod-2;t;t>>=1,b=b*b%mod) if(t&1) ans=ans*b%mod;
     7     return ans;
     8 }
     9 void exgcd(int a,int b,int &x,int &y){
    10     if(!b){x=1;y=0;return;}
    11     exgcd(b,a%b,x,y);
    12     int res=x;x=y;y=res-a/b*x;
    13 }
    14 signed main(){
    15     scanf("%lld%lld%lld%lld",&t,&Mod,&n,&m);
    16     if(n<0)n=-n; if(m<0)m=-m;
    17     if(t<n+m){puts("0");return 0;}
    18     if(t-n-m&1){puts("0");return 0;}
    19     for(int mm=Mod,i=2;i<=100000;++i)
    20         if(mm%i==0)mod[++mods]=i,mm/=i;
    21         else if(i==100000&&mm!=1)mod[++mods]=mm;
    22     for(int modi=1;modi<=mods;++modi){
    23         int na=n,a=0,mb=m+(t-n-m)/2,b=(t-n-m)/2,C=1,tms=0;
    24         for(int i=1;i<=t;++i){
    25             int res=i;
    26             while(res%orz==0)tms++,res/=orz;
    27             C=C*res%orz;
    28         }//printf("-%lld %lld
    ",C,tms);
    29         for(int i=1;i<=na;++i){
    30             int res=i;
    31             while(res%orz==0)tms--,res/=orz;
    32             C=C*pow(res,orz)%orz;
    33         }//printf("--%lld %lld
    ",C,tms);
    34         for(int i=1;i<=mb;++i){
    35             int res=i;
    36             while(res%orz==0)tms--,res/=orz;
    37             C=C*pow(res,orz)%orz;
    38         }//printf("---%lld %lld
    ",C,tms);
    39         for(int i=1;i<=b;++i){
    40             int res=i;
    41             while(res%orz==0)tms--,res/=orz;
    42             C=C*pow(res,orz)%orz;
    43         }//printf("----%lld %lld
    ",C,tms);
    44         ans[modi]=(ans[modi]+(tms?0:C))%orz;
    45         while(b){
    46             b--;mb--;a++;na++;int res;
    47             res=b+1;while(res%orz==0)tms++,res/=orz;C=C*res%orz;
    48             res=mb+1;while(res%orz==0)tms++,res/=orz;C=C*res%orz;
    49             res=a;while(res%orz==0)tms--,res/=orz;C=C*pow(res,orz)%orz;
    50             res=na;while(res%orz==0)tms--,res/=orz;C=C*pow(res,orz)%orz;
    51             (ans[modi]+=(tms?0:C))%=orz;//printf("-----%lld %lld
    ",C,tms);
    52         }
    53         exgcd(Mod/orz,orz,x,y); x*=ans[modi]; x=(x%orz+orz)%orz;
    54         (Ans+=Mod/orz*x%Mod)%=Mod;
    55     }
    56     //for(int i=1;i<=mods;++i)printf("%lld %lld
    ",mod[i],ans[i]);
    57     printf("%lld
    ",Ans);
    58 }
    形式化地放着
  • 相关阅读:
    Win10以管理员身份运行Loadrunner11时候提示“管理员已阻止你运行此应用”
    logrotate日志切割
    Scala的型变
    Caused by: com.esotericsoftware.kryo.KryoException: Buffer overflow. Available: 0, required: 134217728
    ERROR BatchJobMain: Task not serializable
    Spark创建HiveContext报错tez的问题
    Spark初始换HiveContext空指针异常
    windows10专业版 操作系统无法监听远程端口
    windows环境如何上传项目到gitee
    canal-kakfa-flink实现mysql数据的实时同步(一)
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11227874.html
Copyright © 2011-2022 走看看