1479 小Y的数论题
基准时间限制:1.5 秒 空间限制:131072 KB
分值: 640 难度:8级算法题
小Y喜欢研究数论,并且喜欢提一些奇怪的问题。
这天他找了三个两两互质的数a, b, c,以及另一个数m, 现在他希望找到
三个(0, m)范围内的整数x, y, z,使得
(x^a+y^b) Mod m=(z^c) Mod m
Input
第一行一个数代表数据组数T
接下来T行每行四个整数m, a, b, c
满足a, b, c两两互质
1 <= T <= 100000
1 <= a, b, c <= 10^9
3 <= m <= 10^9
Output
对于每组数据,如果不存在x, y, z满足条件,则输出”Stupid xiaoy”(不含引号)
否则输出一行三个数分别为x, y, z
Input示例
1
100 1 1 1
Output示例
1 2 3
考虑构造形如 2^kab+2^kab=2^(kab+1) 的式子
那么只要找到合理的k使得(kab + 1)能被c整除,就可以构造出满足条件的x y z
设
kab+1=lc
那么有
lc−kab=1
可以用扩展欧几里得解这个不定方程
此时存在的唯一问题是,若m是2的次幂,那么取模之后结果可能是0
这种情况可以特殊处理,例如:
若a > 1,取x = m / 2, y = z = 1
b > 1类似
否则若c > 1, 取x = y = z = m / 2
否则取x = y = 1, z = 2
#include<stdio.h>
#include<iostream>
#include<math.h>
using namespace std;
#define ll long long
ll a,b,c,k,l,x,y,z;
ll mod;
ll quick_mod(ll m,ll n){
ll b=1;
while(n){
if(n&1){
b=b*m%mod;
}
n>>=1;
m=m*m%mod;
}
return b;
}
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;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%lld %lld %lld %lld",&mod,&a,&b,&c);
if(quick_mod(2,mod)==0){
x=1,y=1,z=1;
if(a>1)x=mod/2;
else if(b>1)y=mod/2;
else if(c>1)x=y=z=mod/2;
else x=y=1,z=2;
printf("%lld %lld %lld\n",x,y,z);
continue;
}
exgcd(c,a*b,l,k);
k=-k;
while(k<0||l<0)k+=c,l+=a*b;
x=quick_mod(2,b*k);y=quick_mod(2,a*k);z=quick_mod(2,l);
printf("%lld %lld %lld\n",x,y,z);
}
return 0;
}