费马小定理,拓展欧几里得求逆元。zzuli 2180

来源:互联网 发布:金融网络理财产品排行 编辑:程序博客网 时间:2024/04/29 02:19

逆元:在mod m的运算下,像满足

ax%m=1
这样的求解出的x,我们称作a的逆元即
a1

首先简介费马小定理 传送门
对于p是素数时,任意正整数都有
(xp)%p=x

然后可以推出
(xp1)%p=1

最后可以变形得到

x1%p=xp2

所以我们对于一个数求x^(p-2)就是他的逆元.

拓展欧几里得的做法,也很显然,就是求解ax + km = 1中的x就是a的逆元。

例题zzuli 2180 传送门

这个题就是求一个等比数列的前n项和,直接套用公式,不过在公式最后一部分处罚的时候要求一下逆元
代码如下

#include<cstdio>#include<cstring>#include<cmath>#include<vector>#include<algorithm>#include<iostream>#include<set>#include<queue>using namespace std;typedef long long ll;const ll mod = (ll)1e9+7;ll Quick_pow(ll x,ll n){    ll res = 1;    while(n){        if(n&1) res = res%mod*x%mod;        x = x%mod*x%mod;        n = n >> 1;    }    return res;}ll extgcd(ll a,ll b,ll &x,ll &y){    ll res = 0;    if(b != 0) {        res = extgcd(b,a%b,y,x);        y -= (a/b)*x;    }else{        x = 1;y = 0;    }    return res;}ll mod_inverse(ll a,ll m){    ll x,y;    extgcd(a, m, x, y);    return (m + x%m)%m;//这里是为了保证x是最小的正整数}int main(void){    ll k,n,Case = 0;    while(scanf("%lld %lld",&k,&n) != EOF){        printf("Case %lld: ",++Case);        if(k == 1)  printf("%lld\n",n+1);        else{            ll p = Quick_pow(k,n+1) - 1;            ll q = k - 1;   //         ll x,y;       //     ll b = Quick_pow(q,mod-2);            ll add = mod_inverse(q,mod);            printf("%lld\n",(p%mod)*add%mod);        }    }    return 0;}/**************************************************************    Problem: 2180    User: zhao5502169    Language: C++    Result: Accepted    Time:0 ms    Memory:1368 kb****************************************************************/
原创粉丝点击