版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/C20181220_xiang_m_y/article/details/88959319
题面:
Description
已知k,a,p,求x ^ k=a (mod p)的所有根(根的范围[0,p-1],P为质数
Input
三个整数p,k,a。0 < = a <p < = 10^9, 2 < = k < = 100000
Output
第一行一个整数,表示符合条件的x的个数。
第二行开始每行一个数,表示符合条件的x,按从小到大的顺序输出。
题目分析:
设p的原根为g,那么g的1到
次幂模p互不相等。
因为p是质数,所以任意一个数在模p意义下都可以用g的几次幂来表示。
(更一般的,一个与m互质的数都可以用m的原根的几次幂来表示)
设
表示x是g的几次幂,即:
;
那么原方程就是
就是要求
用BSGS求出
,然后用exgcd求出所有满足条件的
即可。
数学题做起来真是有种异样的感觉。。
Code:
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<map>
#define maxn 100005
using namespace std;
int pr[maxn],cnt;
inline int exgcd(int a,int b,int &x,int &y){
if(!b) {x=1,y=0;return a;}
else {int d=exgcd(b,a%b,y,x);y-=a/b*x;return d;}
}
inline int ksm(int a,int b,int p){
int s=1;
for(;b;b>>=1,a=1ll*a*a%p) if(b&1) s=1ll*s*a%p;
return s;
}
void getprime(int p){
for(int i=2;i*i<=p;i++) if(p%i==0){
pr[++cnt]=i;
while(p%i==0) p/=i;
}
if(p>1) pr[++cnt]=p;
}
int getrg(int p){
if(p==2) return 1;
getprime(p-1);
for(int i=2;i<p;i++){
for(int j=1;j<=cnt;j++) if(ksm(i,(p-1)/pr[j],p)==1) goto he;
return i; he:;
}
}
int BSGS(int a,int b,int p){
if(b==1) return 0;
int m=int(sqrt(p)+1),base=b;
map<int,int>has;
for(int i=0;i<m;i++) has[base]=i,base=1ll*base*a%p;
int now=1;base=ksm(a,m,p);
for(int i=1;i<=m;i++)
if(has.count(now=1ll*now*base%p)) return i*m-has[now];
return -1;
}
int ans[maxn],tot;
int main()
{
int k,a,p;
scanf("%d%d%d",&p,&k,&a);
if(a==0) return printf("1\n0"),0;
int g=getrg(p);
int A=BSGS(g,a,p),x,y;
int d=exgcd(k,p-1,x,y);
if(A==-1||A%d) return puts("0"),0;
int sp=(p-1)/d; x=(1ll*x*A/d%sp+sp)%sp;
if(!x) x=sp;//x->phi[p]=p-1
for(int i=x;i<p;i+=sp) ans[++tot]=ksm(g,i,p);
sort(ans+1,ans+1+tot);
printf("%d\n",tot);
for(int i=1;i<=tot;i++) printf("%d%c",ans[i],i==tot?10:32);
}