【JZOJ 3909】Idiot 的乘幂
题面:
正文:
把题目中的方程组组合在一起就变成了:
\(X^{a+c}\equiv b \cdot d (\mod p)\)
那这时,我们假定两个数\(x\)和\(y\),使得:
\(ax + cy = 1\)
于是:
\(X^{ax+cy}\equiv X \equiv b^x \cdot d^y (\mod p)\)
那我们就可以根据\(ax+cy=1\)跑一遍扩欧,再根据\(X \equiv b^x \cdot d^y (\mod p)\),就能得出\(X\)了。
但是,你以为出题人这么善良吗?
\(x\)和\(y\)可能是负数,做\(b^x \cdot d^y\) 时就相当于 \(\frac{1}{b^{(-x)}} \cdot \frac{1}{d^{(-y)}}\), 因为有膜法技能同余,这里肯定出锅。
所以我们还要给\(b\)和\(d\)求个逆元,同样,也是用扩欧。
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ZYC using
#define AK namespace
#define IOI std
#define ll long long
ZYC AK IOI;
const int N = 0;
ll exgcd(ll a, ll b, ll &x, ll &y)
{
if(b == 0)
{
x = 1, y = 0;
return a;
}
ll val = exgcd(b, a % b, y, x);
y -= a / b * x;
return val;
}
ll qpow(ll a, ll b, ll p)
{
ll ans = 1;
for (; b; b >>= 1)
{
if(b & 1) ans = (ans * a+p) % p;
a = (a * a+p) % p;
}
return ans;
}
ll t, a, b, c, d, bf, df, p, x, y, X, public_;
int main()
{
for(scanf("%lld", &t); t--;)
{
scanf("%lld%lld%lld%lld%lld", &a, &b, &c, &d, &p);
exgcd(a, c, x, y);
bf = b, df = d;
if (x < 0)
exgcd(b, p, bf, public_), x = -x;
if (y < 0)
exgcd(d, p, df, public_), y = -y;
X = qpow((bf % p + p)%p, x, p) * qpow((df % p + p)%p, y, p)%p ;
if((qpow(X, a, p) == b % p) && (qpow(X, c, p) == d % p))
printf("%lld\n", X);
else puts("No Solution!");
}
return 0;
}