逆元求法 费马小定理

参考:https://blog.csdn.net/weixin_30616969/article/details/97875284
参考:https://www.luogu.com.cn/problem/solution/P3811
题目:https://www.luogu.com.cn/problem/P5684

在这里插入图片描述
证明:
乘法逆元:
定义: 满足ak≡1 (mod p)的k值就是a关于p的乘法逆元。
为什么要有乘法逆元呢?
当我们要求(a/b) mod p的值,且a很大,无法直接求得a/b的值时,我们就要用到乘法逆元。 我们可以通过求b关于p的乘法逆元k,将a乘上k再模p,
即(a
k) mod p。其结果与(a/b) mod p等价。
证:(其实很简单。。。) 根据bk≡1 (mod p)有bk=px+1。 k=(px+1)/b。
把k代入(ak) mod p,得:
(a
(px+1)/b) mod p =((apx)/b+a/b) mod p
=[((a
px)/b) mod p +(a/b)] mod p
=[(p
(ax)/b) mod p +(a/b)] mod p
// p
[(a*x)/b] mod p=0
所以原式等于:(a/b) mod p

即a/b(mod p)=ab的逆元%p=ab^(p-2)%p

在这里插入图片描述
在这里插入图片描述
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MO=1000000007;
ll n,odd,ans;
char s[2100];
ll fac[2100],sum[200];
ll power(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1)res=res*a%MO;
        a=a*a%MO;
        b/=2;
    }
    return res;
}
int main(){
    cin>>n;
    cin>>s;
    fac[1]=1;
    for(int i=2;i<=n;i++){
        fac[i]=fac[i-1]*i%MO;
    }
    for(int i=0;i<n;i++){
        sum[s[i]]++;
    }
    for(int i='a';i<='z';i++){
        if(sum[i]%2==1){
            if(odd>0){
                cout<<fac[n]<<endl;
                return 0;
            }
            odd=i;
        }
    }
    ans=1;
    if(odd){
        ans=ans*sum[odd]%MO;
        sum[odd]--;
    }
    ans=ans*fac[n/2]%MO;
    for(int i='a';i<='z';i++){
        if(sum[i]>0){
            ans=ans*fac[sum[i]]%MO;
            ans=ans*power(fac[sum[i]/2],MO-2)%MO;
        }
    }
    cout<<(MO+fac[n]-ans)%MO<<endl;
    return 0;
}

求i=1-n之间的所有i!的逆元。

一般多用在组合数预处理中。
参考:https://www.luogu.com.cn/problem/solution/P3811
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值