//方法一: 扩展欧几里得 (求逆元 调用mod_reverse函数)
// 限定条件 a n 互质 log(n)
// @a 数
// @n 模数
inline long long mod_reverse(long long a,long long n)
{
long long x,y,d=extend_gcd(a,n,x,y);
if(d==1) {
if(x%n<=0)return x%n+n; // 答案是负的要置为正的.
else return x%n;
} else return -1ll;
}
// 限定条件 a b 互质
// @a 是 这个数
// @b 是 模数
// @x 是 返回的逆元 返回-1 表示没有逆元
// @y 暂时不知道是什么...
long long extend_gcd(long long a,long long b,long long &x,long long &y)
{
if(a==0&&b==0)
return -1ll;
if(b==0)
{
x=1ll;
y=0ll;
return a;
}
long long d=extend_gcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
//方法二: 费马小定理
// 模数是一个质数 复杂度 log(n)
// 原理, 当p是一个质数时,有 inv(a) = a^(p-2) % p;
long long pwr4(long long a, long long k, long long jmod) {
long long res = 1, base = a;
while (k) {
if (k&1) res = res * base % jmod;
base = base * base % jmod;
k >>= 1;
}
return res;
}
long long mod_reverse(long long a, long long n)
{
return pwr4(a, n-2, n);
}
//方法三: 欧拉定理
// 模数不是质数的情况
// 由a^φ(p)≡ 1(mod p) 得 a^(φ(p)−1)是a的逆元
// φ(p)是欧拉函数
// O(n)的时间可以递推出1~n在 mod p 意义下的逆元
// 没用过 所以先给出别人的代码 kuangbin大神板子也有代码.
void inv3(LL mod)//线性递推求逆元
{
inv[1]=1;
for(int i=2;i<=mod-1;i++)
{
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
cout<<inv[i]<<" ";
}
}