题目描述
小Y喜欢研究数论,并且喜欢提一些奇怪的问题。
这天他找了三个两两互质的数a, b, c,以及另一个数m, 现在他希望找到三个(0, m)范围内的整数x, y, z,使得
(x^a+y^b) Mod m=(z^c) Mod m
有T组询问
1 <= T <= 100000
1 <= a, b, c <= 10^9
3 <= m <= 10^9
做法很机智
考虑这样的式子
2^kab+2^kab=2^(kab+1)
设x=2^kb,y=2^ka
当c|kab+1时必有合法的z
设c*l=kab+1,则cl-kab=1。
注意a,b,c两两互质,所以gcd(c,ab)=1
用扩展欧几里得即可算出l。
z=2^l
若m是2的幂数,余数为0怎么办?
更好办了。。。
当a>1时x=m/2,y=z=1
否则当b>1时 类似
再否则当c>1时 x=y=z=m/2
若a=b=c=1,x=y=1,z=2
注意
l,k算出来后可能比0小,该怎么做大家都明白吧
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define ll long long
using namespace std;
int i;
bool pc(int x){
while (x%2==0) x=x/2;
if (x==1) return 1;return 0;
}
void gcd(ll a,ll b,ll &x,ll &y){
if (b==0){
x=1;y=0;
return;
}
gcd(b,a%b,y,x);
y=y-a/b*x;
}
ll qs(ll y,ll p){
if (y==0) return 1;
if (y==1) return 2;
ll s=qs(y/2,p),s1=qs(y%2,p);
return s*s%p*s1%p;
}
int main(){
int t;scanf("%d",&t);
fo(i,1,t){
ll m,a,b,c,x,y,z,l,k;
scanf("%lld%lld%lld%lld",&m,&a,&b,&c);
if (pc(m)){
if (a>1) x=m/2,y=z=1;else
if (b>1) x=z=1,y=m/2;else
if (c>1) x=y=z=m/2;else
x=y=1,z=2;
}else{
gcd(c,a*b,l,k);
if ((l<0)||(k>0)) {
ll cnt=max(-l/(a*b)+1,k/c+1);
k-=cnt*c;
l+=cnt*a*b;
}k=-k;
x=qs(k*b,m);
y=qs(k*a,m);
z=qs(l,m);
}
printf("%lld %lld %lld\n",x,y,z);
}
}