小Y喜欢研究数论,并且喜欢提一些奇怪的问题。
这天他找了三个两两互质的数a, b, c,以及另一个数m, 现在他希望找到三个(0, m)范围内的整数x, y, z,使得
(xa+yb)modm=(zc)modm
这道构造题,好机智啊!
因为存在很多解,我们看看存不存在以2为底的解。
因为 2a+2a=2a+1 ,所以 2abk+2abk=2abk+1 。
所以设 x=2bk , y=2ak ,存在 xa+yb=2abk+1 。
因为有 xa+yb=zc ,所以mod m意义下, abk+1=lc ,那么就有 lc−abk=1 ,所以可以用扩展gcd求出可行解,但是可能求出来的l或k是小于0的,所以需要找到都大于等于0的解。
最后成功!
机制的方法……
如果m是2的幂数,那么就可以特判一下直接输出答案。
当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
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
ll i,j,k,l,t,n,m,ans,q,a,b,c,x,y,z;
bool bz;
void exgcd(ll a,ll b,ll &x,ll &y){
if (!b){
x=1;y=0;
return;
}
ll xx,yy;
exgcd(b,a%b,xx,yy);
x=yy;y=xx-a/b*yy;
}
ll qsm(ll x,ll y){
ll z=1;
while(y){
if(y&1)z=z*x%m;
x=x*x%m;
y/=2;
}
return z;
}
int main(){
for(scanf("%lld",&q);q;q--){
scanf("%lld%lld%lld%lld",&m,&a,&b,&c);
j=m;bz=1;
while(j){
if(j==2)break;
if(!(j%2))j/=2;
else{
bz=0;
break;
}
}
if(!bz){
ll l,k;
exgcd(c,a*b,l,k);k=-k;
while(k<0||l<0)k+=c,l+=a*b;
x=qsm(2,b*k);y=qsm(2,a*k);z=qsm(2,l);
printf("%lld %lld %lld\n",x,y,z);
}
else{
if(a>1){
printf("%lld 1 1\n",m/2);
}
else if(b>1){
printf("1 %lld 1\n",m/2);
}
else if(c>1){
printf("%lld %lld %lld\n",m/2,m/2,m/2);
}
else if(a==b==c){
printf("1 1 2\n");
}
}
}
}