小Y的數論題

題目描述

小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);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章