SCUT - 492 - 鬼符「搦手的鬼畜生」 - 简单数学

https://scut.online/p/492

求[1,a]范围内的a模m的逆元的数量。

一开始用扩展欧几里得算法草了一发,WA了,当时不太清楚模非质数的周期,看来扩展欧几里得算法的笔记才知道要加上m/(gcd(a,m)),但实际上用扩展欧几里得算法能求出逆元,gcd(a,m)必然是1,所以实际上是要特判掉p=1的情况。事实上p=1不可能会有什么逆元。这或许是扩展欧几里得算法求逆元的一个小问题。

事实上,扩展欧几里得算法忠实地求出了ax+by=gcd(a,b) mod c也就是ax+1=1 mod 1的解x0=0,y0=1,而x=x0+bt,y=y0+at,这两个的确是通解(两边无论是啥模了都是等于0,事实上任意的x,y都是这个方程的解)!也就是之前的模板里面,当p=1的时候,非常特殊。和乘法逆元的时候一样特殊。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll a, p;

ll exgcd(ll a, ll b, ll &x, ll &y) {
    if(!a && !b)
        return -1;
    if(!b) {
        x = 1, y = 0;
        return a;
    }
    ll d = exgcd(b, a % b, y, x);
    y -= (a / b) * x;
    return d;
}

ll inv_rp(ll a, ll p) {
    if(p == 1)
        return -1;
    ll x, y;
    if(exgcd(a, p, x, y) == 1)
        return (x % p + p) % p;
    return -1;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    while(~scanf("%lld%lld", &a, &p)) {
        ll inva = inv_rp(a % p, p);
        if(inva == -1 || p == 1)
            puts("0");
        else
            printf("%lld\n", (a / p) + (a % p >= inva));
    }
}
posted @ 2019-08-19 10:41  韵意  阅读(302)  评论(0编辑  收藏  举报