題目描述
小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);
}
}