互质:原地址
洛谷P3846模板:
//x的多少次方同余于y (mod p) //将x拆分 移项 #include<bits/stdc++.h> using namespace std; map<int,int> mp; int x,y,mod; int quick_pow(int a,int k) { int ans=1; while(k){ if(k&1) ans=1ll*ans*a%mod; k>>=1; a=1ll*a*a%mod; } return ans; } int main() { scanf("%d%d%d",&mod,&x,&y); if(x%mod==0&&y) {puts("no solution");return 0;}//记得要特判 //+1是因为sqrt向下取整 有可能最大值达不到mod int m=sqrt(mod)+1,left=y;//left的初始值是式子右边的y 因为这时m=0 for(int j=0;j<=m-1;j++)//枚举j j是i*m-j的j mp[left]=j,left=1ll*left*x%mod; int t=quick_pow(x,m),s=1; for(int i=1;i<=m;i++){ s=1ll*s*t%mod;//map查找元素的操作:mp.count() 复杂度比hash多了一个log if(mp.count(s)) { printf("%d\n",m*i-mp[s]); return 0; } } printf("no solution\n"); } /* 5 2 3 ans 3 */
不互质:先消因子,再用原BSGS
洛谷P4195模板:
//洛谷要开O2才过的了。。。 /* 思路:对于模数不是质数的情况 先消除因子 再用原BSGS解决 取gcd(a,p) 用b与p约去约数 */ #include<bits/stdc++.h> using namespace std; #define ll long long ll p; map<ll,ll> mp; ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } ll quick_pow(ll a,ll k) { ll ans=1; while(k){ if(k&1) ans=ans*a%p; a=a*a%p; k>>=1; } return ans; } ll exbsgs(ll a,ll b) { a%=p;b%=p; ll c=1; if(b==1)return 0; for(ll i=0;i<=30;i++)//先暴+力处理前面小于cnt if(quick_pow(a,i)%p==b%p) return i; ll cnt=0;//消除因子 for(ll g=gcd(a,p);g!=1;g=gcd(a,p)){ if(b%g) return -1; b/=g;p/=g;c=c*(a/g)%p;cnt++; if(b==c) return cnt;//说明找到一个可行解cnt a^cnt/x^cnt(=)b/x^cnt (=)为同余 } mp.clear(); ll m=(ll)sqrt(p)+1,left=b;//下面是原bsgs 现在方程已经化简成:d*a^(ans-cnt)(=)b(mod p) d*a^(ans-cnt)其实等于a^x for(ll j=0;j<m;j++){ mp[left]=j; left=left*a%p; //用mp会多一个log } left=quick_pow(a,m)%p; for(ll i=1;i<=m+1;i++){ c=c*left%p; if(mp.count(c))return i*m-mp[c]+cnt;//+cnt是因为求出来的是ans-cnt 由上面的方程可知 } return -1; } int main() { while(1){ ll a,b; scanf("%lld%lld%lld",&a,&p,&b); if(p==0) break; ll ans=exbsgs(a,b); if(ans!=-1) printf("%lld\n",ans); else printf("No Solution\n"); } return 0; }