Description
求满足 \(x^k\equiv a \ (mod\ p)\) 的所有的 \(x\)
且 \(x\in[0,p-1]\)
保证 \(p\) 为质数
Solution
先把 \(a=0\) 的判掉
我们发现一般的 \(bsgs\) 可以求指数,但是不能求底数
那么我们转化一发:
原根科技!!!
求原根啥的 \(51nod\) 上面有题做
我们发现 \(p\) 是个素数,就会有原根
我们就可以把右边表示成
\[g^{id_a} \]
左边也就成了:
\[(g^{id_x})^k \]
所以推推式子:
这个\(id_x\times k\equiv id_a \ (mod\ \varphi(p))\)
理解:指数上有欧拉定理……
\(id_a\) 是可以 \(bsgs\) 求的,\(k\) 是个给的
然后就上 \(exgcd\) 把 \(id_x\) 的解和通解求一求
最后输出就 \(OK\)
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
inline int read()
{
int res=0,f=1; char k;
while(!isdigit(k=getchar())) if(k=='-') f=-1;
while(isdigit(k)) res=res*10+k-'0',k=getchar();
return res*f;
}
inline int ksm(int x,int y,int p)
{
int res=1; for(;y;y>>=1,(x*=x)%=p) if(y&1) (res*=x)%=p;
return res;
}
inline void exgcd(int a,int b,int &x,int &y)
{
if(!b) return x=1,y=0,void();
exgcd(b,a%b,x,y); int t=x; x=y;
y=t-(a/b)*y;
return ;
}
const int N=2e5+10;
int d[N],cnt,p,k,a;
inline bool check(int x)
{
for(int i=1;i<=cnt;++i) if(ksm(x,(p-1)/d[i],p)==1) return 0;
return 1;
}
inline int find(int p)
{
int t=p-1;
for(int i=2;i*i<=t;++i)
{
if(t%i!=0) continue;
d[++cnt]=i; while(t%i==0) t/=i;
} if(t!=1) d[++cnt]=t;
int g=1; while(g<p) if(check(g)) return g; else g++;
return -1;
}
map<int,int> mp;
inline int bsgs(int y,int z,int p)
{
int s=ceil(sqrt(p)),t=z%p; mp[t]=0;
for(int i=1;i<=s;++i) (t*=y)%=p,mp[t]=i;
int base=ksm(y,s,p),now=1;
for(int i=1;i<=s;++i)
{
(now*=base)%=p;
if(!mp.count(now)) continue;
int t=i*s-mp[now];
return (t%p+p)%p;
}
}
int num,out[N];
signed main()
{
p=read(); k=read(); a=read();
if(!a) return puts("1\n0"),0;
int g=find(p),ans=bsgs(g,a,p);
int gcd=__gcd(k,p-1);
if(ans%gcd) return puts("0"),0;
int A=k/gcd,B=(p-1)/gcd,x,y;
exgcd(A,B,x,y);
(x+=B)%=B; x=(x*(ans/gcd)+B)%B;
while(x<p-1)
{
out[++num]=ksm(g,x,p);
x+=B;
} sort(out+1,out+num+1);
printf("%lld\n",num);
for(int i=1;i<=num;++i) printf("%lld\n",out[i]);
return 0;
}
}
signed main(){return yspm::main();}
Review
如果出现了底数不好求的情况
我们用原根把底数的计算转到质数上再进行其他操作