参考资料
一.阶
1.定义:设(a,p)是互质整数,必定有(x)满足(a^xequiv 1pmod{p}),最小的满足条件的正整数(x)称为(a)模(p)的阶,记为(Ord_p(a)),如果(gcd(a,p)!=1),则不存在阶。
2.性质:
<1>设(a,p)是互质整数,存在(x')满足(a^{x'}equiv 1pmod{p}),则(Ord_p(a)|x')。
<2>设(a,p)是互质整数,有(Ord_p(a)|varphi(p))(根据欧拉定理反证)。
二.原根
1.定义:设(a,p)为互质整数,若(Ord_p(a)=varphi(p)),则称(a)是模(p)的一个原根。
2.性质:
<1>只有(2,4,p^k,2*p^k)((p)是奇素数)有原根。
<2>一个数(p)若存在原根,则它有(varphi(varphi(p)))个原根。
<3>(a)是(p)的原根,(a^0,a^1,a^2...a^{Ord_p(a)-1})模(p)两两不同。即当(a)是(p)的原根时,(a^0,a^1,a^2...a^{Ord_p(a)-1})构成了模(p)的简化剩余系。
3.求一个数的原根:
暴力:
从(2)开始暴力枚举(x),要求(gcd(x,p)=1),之后检验(x)是否为(p)的原根。
由于(Ord_P(x)|varphi(p)),我们需要检验对于任意(d|varphi(p))且(d
ot=varphi(p)),是否都满足(x^d
otequiv 1pmod{p})。
优化:
由于如果(x^kequiv 1pmod{p}),则(x^{kd}equiv 1pmod{p})
设(varphi(p)=prod_{i=1}^k p_i^{c_i})。
只需要对每个(i)验证是否满足(x^{frac{varphi(p)}{p_i}}
otequiv 1pmod{p}),因为(frac{varphi(p)}{p_i})是除去分解后次幂中含有(p_i^{c_i})以外的所有约数的倍数。这样就相当于判掉了所有(varphi(n))的约数。
三.指标
1.定义:设(g)是模(p)的一个原根,整数(a)与(p)互质,则存在唯一的整数(x)满足:(g^xequiv apmod{p}),称(x)为以(g)为底对模(p)的一个指标。记为(x=ind_ga)。
2.性质:
<1>(aequiv bpmod{p}->ind_gaequiv ind_gbpmod{varphi(p))})
<2>(ind_g(ab)equiv ind_ga+ind_gbpmod{varphi(p)})
<3>(ind_g(a^k)equiv k*ind_gapmod{varphi(p)})
3.求指标:直接(BSGS)即可。
四.N次剩余问题(转自)
求解(x^kequiv apmod{p}),p是质数。
先求出(p)的最小原根(g),因为p是质数,因此必定存在(ind_gx)与(ind_ga)。
所求即变为(k*ind_gxequiv ind_gapmod{varphi(p)})。
用(exgcd)解出即可。
模板题
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a,K,mod,g,t,x,y,d;
vector<int>prime,ans;
inline int power(int x,int k,int mod)
{
int res=1;
while(k)
{
if(k&1)res=res*x%mod;
x=x*x%mod;k>>=1;
}
return res;
}
inline int find(int p)
{
int tmp=p-1;
for(int i=2;i*i<=tmp;i++)
{
if(tmp%i)continue;
prime.push_back(i);
while(tmp%i==0)tmp/=i;
}
if(tmp>1)prime.push_back(tmp);
for(int g=1;g<=p;g++)
{
bool flag=1;
for(unsigned int i=0;i<prime.size();i++)
if(power(g,(p-1)/prime[i],p)==1){flag=0;break;}
if(flag)return g;
}
return -1;
}
inline int BSGS(int a,int b,int mod)
{
if(b==1)return 0;
if(!a)return !b?1:-1;
map<int,int>mp;mp.clear();
int t=ceil(sqrt(mod));
for(int i=0,j=1;i<=t;i++,j=j*a%mod)mp[b*j%mod]=i;
a=power(a,t,mod);
for(int i=1,j=a;i<=t;i++,j=j*a%mod)if(mp.count(j))return i*t-mp[j];
return -1;
}
int exgcd(int a,int b,int &x,int &y)
{
if(!b){x=1,y=0;return a;}
int d=exgcd(b,a%b,x,y);
int z=x;x=y,y=z-(a/b)*y;
return d;
}
signed main()
{
scanf("%lld%lld%lld",&mod,&K,&a);
if(!a){puts("1");puts("0");return 0;}
g=find(mod);t=BSGS(g,a,mod);
//cerr<<"test::"<<g<<' '<<t<<endl;
d=exgcd(K,mod-1,x,y);
if(t%d){puts("0");return 0;}
int P=(mod-1)/d;
x=(x*(t/d)%P+P)%P;
while(x<mod)
{
ans.push_back(power(g,x,mod));
x+=P;
}
sort(ans.begin(),ans.end());
printf("%lld
",ans.size());
for(int i=0;i<ans.size();i++)printf("%lld
",ans[i]);
return 0;
}