zoukankan      html  css  js  c++  java
  • 51nod1119(除法取模/费马小定理求组合数)

    题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1119

    题意:中文题诶~

    思路:这题数据比较大直接暴力肯定是不行咯,通过一部分打表我们不难发现这个矩阵就是由两个杨辉三角构成的,那么求f(n, m)就是求组合数c(m+n-2, m-1)%mod,其中n>=m;

    我们令m+n-2=n, m-1=m, 即我们要求c(n, m)=n!/((n-m)!*m!)%mod,为了书写方便,我们再令:a=n!/(n-m)!, b=m!;

    那么我们现在要求的就是:(a/b)%mod,除法取模并不能直接计算,我们需要将之转化为乘法取摸运算;

    接下来我们可以有两种解法:

    解法1:(a/b)%mod=(a*b')%mod,其中b'为b%mod的乘法逆元,求乘法逆元我们直接用exgcd就好了;不过这里还有一个问题需要注意:

    a, b两个数本身就已经超过long long了,所以我们不能先直接计算出a, b的值再求逆元;那么我们是否可以在计算a, b的过程中给其取摸呢?

    即:((a%mod)/(b%mod))%mod=?((a%mod)*b')%mod,  答案是可以的, 因为:b=1(%mod), 那么有 b%mod=1(%mod),  显然,先给b取摸再求逆是可行的。 所以我们最终要求的就是:((a%mod)*b')%mod;

    代码:

     1 #include <bits/stdc++.h>
     2 #define ll long long
     3 using namespace std;
     4 
     5 const ll mod=1e9+7;
     6 
     7 void exgcd(ll a, ll b, ll&x, ll&y){
     8     if(!b){
     9         y=0, x=1;
    10         return;
    11     }
    12     exgcd(b, a%b, y, x);
    13     y-=a/b*x;
    14 }
    15 
    16 int main(void){
    17     ll n, m, a=1, b=1, x, y;
    18     cin >> n >> m;
    19     if(n<m){
    20         swap(n, m);
    21     }
    22     n=n+m-2, m-=1;
    23     for(ll i=n,j=0; j<m; j++,i--){
    24         a=i*a%mod;
    25     }
    26     for(ll i=2; i<=m; i++){
    27         b=b*i%mod;
    28     }
    29     exgcd(b, mod, x, y);
    30     x=(x%mod+mod)%mod;
    31     cout << a*x%mod << endl;
    32     return 0;
    33 }

    解法2:

    我们先引入费马小定理:对于互质的两个数b, mod, 有:b^(mod-1)=1(%mod)-----1式;

    本题要求 x=(a/b)%mod, 即: a/b=x(%mod)-----2式;

    联立1,2式,有:a/b*b^(mod-1)=x(%mod), 即:a*b^(mod-2)=x(%mod), 所以:x=a*b^(mod-2) % mod, 我们可以用快速幂求解;

    关于上式证明:

    1式等价于:b^(mod-1)%mod=1; 即: b^(mod-1)=k*mod+1;

    2式等价于:(a/b)%mod=x; 即: a/b=k'*mod+x;

    所以有:a/b*b^(mod-1)=k*k'*mod^2+k'*mod+x*k*mod+x;

    所以:a/b*b^(mod-1)%mod=x;

    所以:a/b*b^(mod-1)=x(%mod), 即原式得证;

    代码:

     1 #include <bits/stdc++.h>
     2 #define ll long long
     3 using namespace std;
     4 
     5 const ll mod=1e9+7;
     6 
     7 ll get_pow(ll x, ll n){
     8     ll ans=1;
     9     while(n){
    10         if(n&1){
    11             ans=ans*x%mod;
    12         }
    13         x=x*x%mod;
    14         n>>=1;
    15     }
    16     return (ans+mod)%mod;
    17 }
    18 
    19 int main(void){
    20     ll n, m, a=1, b=1, x, y;
    21     cin >> n >> m;
    22     if(n<m){
    23         swap(n, m);
    24     }
    25     n=n+m-2, m-=1;
    26     for(ll i=n,j=0; j<m; j++,i--){
    27         a=i*a%mod;
    28     }
    29     for(ll i=2; i<=m; i++){
    30         b=b*i%mod;
    31     }
    32     cout << a*get_pow(b, mod-2)%mod << endl;
    33     return 0;
    34 }
  • 相关阅读:
    Spring Boot教程(三十)使用Spring-data-jpa(1)
    Spring Boot教程(二十九)使用JdbcTemplate操作数据库
    Spring Boot教程(二十八)通过JdbcTemplate编写数据访问
    Spring Boot教程(二十七)整合Spring Security
    Spring Boot教程(二十六)使用Spring Security安全控制
    Spring Boot教程(二十五)返回JSON格式
    gl 绘制多边形的函数解析 分类: OpenGL(转)
    OpenGL超级宝典笔记——画三角形(转)
    OpenGL_Qt学习笔记之_03(平面图形的着色和旋转)(转)
    OpenGL超级宝典笔记——贝塞尔曲线和曲面(转)
  • 原文地址:https://www.cnblogs.com/geloutingyu/p/6287216.html
Copyright © 2011-2022 走看看