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; }