zoukankan      html  css  js  c++  java
  • 求大组合数

    众所周知 ,所以我们只需要求出m!和n!(m-n)!。

    但是由于n和m都偏大,直接乘一定会爆掉(喜闻乐见(●'◡'●))。所以我们首先想到的是边乘边模,但是尝试了一组数据后我们神奇地发现答案不对。

    但是我们知道另一种定理,n!%p=n!边乘边模的逆元。

    所以这时候我们可以利用逆元来解决这个问题。

    而逆元可以运用扩展欧几里得的方法求得。

    下面我们给出欧几里得算法的证明:

    首先我们设k为gcd(a,b),则a=km,b=kn。

    则a%b=a-c*b=km-c*kn=(m-cn)k

    gcd(b,a%b)=gcd(kn,(m-cn)k)

    由于k为a,b的最大公约数,所以n与m-cn互质,所以gcd(b,a%b)=gcd(a,b)=k。

    知道了欧几里得算法,我们可以对其进行延伸得到了扩展欧几里得算法:

    对于任意两个互质的a,b,总有gcd(a,b)=ax+by,扩展欧几里得算法可以用来求解

    x,y。求法:

        根据欧几里得算法可知gcd(a,b)=gcd(b,a%b)。

        则bx‘+(a%b)y'=gcd(a,b)

        将a%b=a-(a/b)*b带入得

        ay'+b(x'-(a/b)*y')=gcd(a,b)

        对于a,b而言,他们对应的x,y则分别为y',(x'-(a/b)*y')。

    而当b=0时,a*1+b*0=gcd(a,b)。

    知道了这些后,此题就变得非常简单了,但是仍有需要注意的地方。

    一:要防止逆元为负数的情况发生。

    二:要注意因子中含有p的倍数,这样变成边模后结果就会变成0.

    对于第一种情况,我们很好解决。对于第二种情况,我们可以先记录因子可以整除p几次后记录,将能整除的除去,剩下的就乘进去取模。

    如果分母中的因子可以整除p的次数和与分子中的相等的话,就照原来的方法输出,否则输出0。

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    代码如下

     1 #include<iostream>
     2 #include<cstdio>
     3 #define LL long long
     4 using namespace std;
     5 LL extgcd(LL a,LL b,LL& x,LL& y)
     6 {
     7     if(b!=0)
     8     {
     9         LL d=extgcd(b,a%b,y,x);
    10         y-=(a/b)*x;
    11         return d;
    12     }
    13     else
    14     {
    15        x=1,y=0;
    16        return a;
    17     }
    18 }
    19 int main()
    20 {
    21     LL m,n,p;
    22     cin>>m>>n>>p;
    23     LL a=1,b=1,c=1;
    24     LL ka=0,kb=0,kc=0;
    25     for(int i=1;i<=m;i++)
    26     {
    27         int temp=i;
    28          while(temp%p==0)
    29           {
    30             temp/=p;
    31             ka++;
    32           }
    33           a=(a*temp)%p;
    34     }
    35      for(int i=1;i<=n;i++)
    36      {
    37         int temp=i;
    38          while(temp%p==0)
    39           {
    40             temp/=p;
    41             kb++;
    42           }
    43           b=(b*temp)%p;
    44      }
    45      for(int i=1;i<=m-n;i++)
    46      {
    47         int temp=i;
    48          while(temp%p==0)
    49           {
    50             temp/=p;
    51               kc++;
    52           }
    53           c=(c*temp)%p;
    54      }
    55     LL x1,x2,y;
    56     extgcd(b,p,x1,y);
    57     x1=(x1%p+p)%p; 
    58     extgcd(c,p,x2,y);
    59     x2=(x2%p+p)%p;
    60     a=((a*x1)%p)*x2%p;
    61     if(ka==kb+kc) cout<<a;
    62     else cout<<0;
    63 }
    View Code
    O(∩_∩)O~ (*^__^*) 嘻嘻…… O(∩_∩)O哈哈~
  • 相关阅读:
    小师妹学JVM之:JIT中的PrintCompilation
    八张图彻底了解JDK8 GC调优秘籍-附PDF下载
    区块链系列教程之:比特币中的网络和区块链
    从印度兵力分布聊聊Mybatis中#和$的区别
    区块链系列教程之:比特币的钱包与交易
    小师妹学JVM之:JIT中的LogCompilation
    从发布-订阅模式谈谈 Flask 的 Signals
    基于 Ajax 请求的 Flask-Login 认证
    解决 openpyxl 垂直分页符和水平分页符同时添加的问题
    用 python 抓取知乎指定回答下的视频
  • 原文地址:https://www.cnblogs.com/wls001/p/5297252.html
Copyright © 2011-2022 走看看