【解高次同余方程】51nod1038 X^A Mod P

1038 X^A Mod P 

基准时间限制:1 秒 空间限制:131072 KB 分值: 320
X^A mod P = B,其中P为质数。给出P和A B,求< P的所有X。
例如:P = 11,A = 3,B = 5。
3^3 Mod 11 = 5
所有数据中,解的数量不超过Sqrt(P)。
 
Input
第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 100)
第2 - T + 1行:每行3个数P A B,中间用空格隔开。(1 <= A, B < P <= 10^9, P为质数)
Output
共T行,每行包括符合条件的X,且0 <= X < P,如果有多个,按照升序排列,中间用空格隔开。如果没有符合条件的X,输出:No Solution。所有数据中,解的数量不超过Sqrt(P)。
Input示例
3
11 3 5
13 3 1
13 2 2
Output示例
3
1 3 9
No Solution

题解

解高次同余方程时,先求出来原根

再用原根代换方程两边(要用到BSGS

转化成一次剩余问题用EX_GCD求解即可

P.S. BSGS用map会T,所以我恬不知耻地贴了一份

代码

//by 减维
#include<set>
#include<map>
#include<queue>
#include<ctime>
#include<cmath>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define il inline
#define rg register
#define db double
#define mpr make_pair
#define maxn 100005
#define inf (1<<30)
#define eps 1e-8
#define pi 3.1415926535897932384626L
using namespace std;

inline int read()
{
    int ret=0;bool fla=0;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-'){fla=1;ch=getchar();}
    while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();}
    return fla?-ret:ret;
}

int t,num,cnt;
ll a,p,b,g,phip,pri[maxn],ans[maxn];
vector<ll> phipri;
map<ll,ll> mp;
bool pd[maxn];

il ll ksm(ll x,ll y,ll mod)
{
    ll ret=1;x%=mod;
    for(;y;y>>=1,x=x*x%mod)
        if(y&1) ret=ret*x%mod;
    return ret;
}

ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(b==0){x=1;y=0;return a;}
    ll gcd=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return gcd;
}

il void pre()
{
    for(int i=2;i<=maxn-5;++i)
    {
        if(!pd[i]) pri[++num]=i;
        for(int j=1;j<=num&&i*pri[j]<=maxn-5;++j)
        {
            pd[i*pri[j]]=1;
            if(i%pri[j]==0) break;
        }
    }
}

il ll getphi(ll x)
{
    ll ret=x;
    for(int i=1;pri[i]*pri[i]<=x;++i)
        if(x%pri[i]==0)
        {
            ret=ret/pri[i]*(pri[i]-1);
            while(x%pri[i]==0) x/=pri[i];
        }
    if(x>1) ret=ret/x*(x-1);
    return ret;
}

il bool check(ll g,ll x,ll p)
{
    int siz=phipri.size();
    for(int i=0;i<siz;++i)
        if(ksm(g,x/phipri[i],p)==1) return 0;
    return 1;
}

il ll getg(ll x,ll p)
{
    ll tmp=x;
    phipri.clear();
    for(int i=2;i*i<=x;++i)
        if(x%i==0)
        {
            phipri.push_back(i);//printf("%lld ",pri[i]);
            while(x%i==0) x/=i;
        }
    if(x!=1) phipri.push_back(x);//,printf("%lld ",x);
    //puts("");
    x=tmp;
    ll gen=1;
    while(1)
    {
        if(check(gen,x,p)) return gen;
        gen++;
    }
}

struct sa{
    long long x;
    int id;
    bool operator<(const sa &b)const{
        if (x == b.x) return id < b.id;
        return x<b.x;
    }
}rec[100500];
//用rec存离散对数
long long bsgs(long long x,long long n,long long m){
    int s=(int)(sqrt((double)m+0.5));
    while((long long)s*s<=m)s++;
    long long cur=1;
    sa tmp;
    for(int i=0;i<s;i++){
        tmp.x=cur,tmp.id=i;
        rec[i]=tmp;
        cur=cur*x%m;
    }
    sort(rec,rec+s);
    //这里不能用map查找比较慢,采用排序二分就快了
    long long mul= ksm(cur, m - 2, m) % m;
    //这里有的方法是在下面的循环里求解快速幂,但本题是不行的  要在循环外面弄,保证时间
    cur=1;

    for(long long i=0;i<s;i++){
        long long more=n*cur%m;
        tmp.x=more,tmp.id=-1;
        int j=lower_bound(rec,rec+s,tmp)-rec;
        if(rec[j].x==more){
            return i*s+rec[j].id;
        }
        cur=cur*mul%m;
    }
    return -1;
}

int main()
{
    t=read();
    pre();
    while(t--){
        p=read(),a=read(),b=read();
        phip=p-1;cnt=0;
        g=getg(phip,p);
        //printf("%lld ",g);
        ll c=bsgs(g,b,p);
        //printf("%lld ",c);
        if(c==-1){puts("No Solution");continue;}
        ll x,y;
        ll gcd=exgcd(a,phip,x,y);
        //printf("%lld ",gcd);
        if(c%gcd!=0){puts("No Solution");continue;}
        x=x*(c/gcd)%phip;
        ll delt=phip/gcd;
        for(int i=0;i<gcd;++i)
        {
            x=((x+delt)%phip+phip)%phip;
            ans[++cnt]=ksm(g,x,p);
        }
        sort(ans+1,ans+cnt+1);
        for(int i=1;i<=cnt;++i) printf("%lld ",ans[i]);puts("");
    }
    return 0;
}

 

posted @ 2018-03-16 18:39  减维  阅读(459)  评论(0编辑  收藏  举报