高次同余方程。 BL == N (mod P)求解最小的L。
/* A^x=B(mod C) 设x=i*m-j(其中m=ceil(sqrt C)) 并且i∈[1,m],j∈[0,m],以保证x能取到所有的0~C-1之间的数。 为什么只取到0~C-1就行了呢? 根据费马小定理 a^(p-1)=1(mod p)(p是素数),我们可以得到 a^(k mod p-1)=a^k(mod p) 即当k>p-1时,会出现类似于循环节的东西。 那么我们可以得到变形之后的式子 A^(i*m-j)=B(mod C) 化简之后为 A^(i*m)=B*A^j(mod C) 现在只需要枚举所有的j,然后把它们放到hash里,再枚举i,得到的第一个即为答案。 */ #include<cstdio> #include<iostream> #include<cmath> #include<map> #define lon long long using namespace std; lon A,B,C; map<lon,int> hash; lon poww(lon a,lon b){ lon base=a,r=1; while(b){ if(b&1) r*=base;r%=C; base*=base;base%=C; b>>=1; } return r; } int main(){ while(scanf("%lld%lld%lld",&C,&A,&B)!=EOF){ if(A%C==0){ printf("no solution "); continue; } hash.clear(); lon m=ceil(sqrt(C)); lon ans; for(int i=0;i<=m;i++){ if(!i){ ans=B%C;hash[ans]=i; continue; } ans=(ans*A)%C;hash[ans]=i; } ans=1;lon t=poww(A,m);bool fl=false; for(int i=1;i<=m;i++){ ans=(ans*t)%C; if(hash[ans]){ ans=i*m-hash[ans]; ans=(ans%C+C)%C; printf("%lld",ans);printf(" "); fl=true; break; } } if(!fl) printf("no solution "); } return 0; }