组合数+费马大/小定理

 

附上一题:  https://ac.nowcoder.com/acm/contest/114/B

有上面的公式2,还不能完全解决问题,这里还要用到阶乘的逆元。

我们都知道对于取模。

 a*b%mod   等价于    ((a%mod)*(b%mod))%mod

但是  (a/b)%mod   与    ((a%mod)/(b%mod))%mod 是非等价关系的。

题目要求取出  C(2*n,n);  的值,  也就是  2*n的阶乘连除以两个n的阶乘,而除法取模不满足结合律,所以此处要用到逆元。

先举一个简单的例子     a/b%mod   可以看成   a  *  pow(b,-1)%mod    那么此处是可以用取模结合律的,pow(b,-1)正是b关于1的逆元。

那么怎么求阶乘的逆元呢?也就是n的阶乘关于mod的逆元呢? 

如果按照上面直接求关于1 的逆元,那么在计算机存储中,肯定是会超过double的精度的。因此这种解法是被否决的。

费马小定理:    假设a为整数,b为质数,且gcd(a,b)的值为1,也就是a,b互质,     那么可得     a^(b-1)%b==1

既然关于1 的逆元会被否决,那么求关于mod的逆元呢?      (证明过程)

a    *   (a关于mod的逆元)%mod的值应等于1 。     根据费马小定理,     a^(mod-1)%mod的值为1           那么a^(mod-1)     是否可以写成  a  *  a^(mod-2)?

综上所述,结论为:

      a关于mod的逆元为    a^(mod-2)%mod ==1

AC代码:

#include<iostream>
#define N 2000010
#define ll long long
using namespace std;
int mod=998244353;
ll a[N],b[N];// 阶乘    和   逆元 
ll quick(ll a,ll b)
{
    ll ans=1;
    while (b){
        if (b&1)
            ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
} 
void init()
{
    a[1]=a[0]=1;
    for (ll i=2;i<N;i++){
        a[i]=a[i-1]*i%mod;
    }
    b[N-1]=quick(a[N-1],mod-2);
    for (ll i=N-2;i>=0;i--){
        b[i]=b[i+1]*(i+1)%mod;
    }
    return ;
}
int main()
{
    ios::sync_with_stdio(false);
    int n;
    init();
    while (cin>>n){
        ll ans=0;
        for (int i=1;i<=n;i++){
            ans=(ans+(a[2*i]*b[i]%mod)*b[i])%mod;
        }
        cout<<ans<<endl;
    }
    return 0;
}

另外补充一下,费马大定理。

问题:a为整数,是否可以把该指数   a^p  (其中p>2)   拆分成两个整数p次幂的和呢?

费马大定理告诉你,这是不可能的。   (证明过程过于复杂,直接贴结论)

x^n+y^n= z^n       (其中x,y,z都是整数)        (费马大定理:当n大于2的时,则该方程不存在整数解。)

原文地址:https://www.cnblogs.com/q1204675546/p/10543951.html