原根与指标
参考资料
一.阶
1.定义:设\(a,p\)是互质整数,必定有\(x\)满足\(a^x\equiv 1\pmod{p}\),最小的满足条件的正整数\(x\)称为\(a\)模\(p\)的阶,记为\(Ord_p(a)\),如果\(\gcd(a,p)!=1\),则不存在阶。
2.性质:
<1>设\(a,p\)是互质整数,存在\(x'\)满足\(a^{x'}\equiv 1\pmod{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\not=\varphi(p)\),是否都满足\(x^d\not\equiv 1\pmod{p}\)。
优化:
由于如果\(x^k\equiv 1\pmod{p}\),则\(x^{kd}\equiv 1\pmod{p}\)
设\(\varphi(p)=\prod_{i=1}^k p_i^{c_i}\)。
只需要对每个\(i\)验证是否满足\(x^{\frac{\varphi(p)}{p_i}}\not\equiv 1\pmod{p}\),因为\(\frac{\varphi(p)}{p_i}\)是除去分解后次幂中含有\(p_i^{c_i}\)以外的所有约数的倍数。这样就相当于判掉了所有\(\varphi(n)\)的约数。
三.指标
1.定义:设\(g\)是模\(p\)的一个原根,整数\(a\)与\(p\)互质,则存在唯一的整数\(x\)满足:\(g^x\equiv a\pmod{p}\),称\(x\)为以\(g\)为底对模\(p\)的一个指标。记为\(x=ind_ga\)。
2.性质:
<1>\(a\equiv b\pmod{p}->ind_ga\equiv ind_gb\pmod{\varphi(p))}\)
<2>\(ind_g(ab)\equiv ind_ga+ind_gb\pmod{\varphi(p)}\)
<3>\(ind_g(a^k)\equiv k*ind_ga\pmod{\varphi(p)}\)
3.求指标:直接\(BSGS\)即可。
四.N次剩余问题(转自)
求解\(x^k\equiv a\pmod{p}\),p是质数。
先求出\(p\)的最小原根\(g\),因为p是质数,因此必定存在\(ind_gx\)与\(ind_ga\)。
所求即变为\(k*ind_gx\equiv ind_ga\pmod{\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\n",ans.size());
for(int i=0;i<ans.size();i++)printf("%lld\n",ans[i]);
return 0;
}