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