P3846 [TJOI2007] 可愛的質數/【模板】BSGS 題解
阿新 • • 發佈:2021-07-17
BSGS本質上是一個分塊演算法。
我們考慮暴力求解的過程,顯然答案的週期為$p$,所以我們只需要求得p之內的答案即可。
此時依然可能有多個解。
這個時候,我們只需要列舉1到p利用快速冪求值即可。
不過這太慢了,我們考慮使用分塊的方法
我們把p分為$m=\sqrt p$塊
我們求出每一塊的端點值即$a^0,a^m,a^{2m},a^{3m}...a^{(m-1)m}$
對於每一個塊的內部,我們預處理出所有可能的值,即$a^0,a^1...a^m$
列舉每一個端點值,查詢端點值內部有沒有某一個點能夠滿足原題條件。
形式化的請看oi-wiki
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<cmath> #define int long long using namespace std; inline int r() { int s=0,k=1;char c=getchar(); while(!isdigit(c)) { if(c=='-')k=-1; c=getchar(); } while(isdigit(c)) { s=s*10+c-'0'; c=getchar(); } return s*k; } int p,b,n; int gcd(int a,int b) { if(!b)return a; return gcd(b,a%b); } map<int,int>m; int pw(int a,int b,int mod) { int base=a,ans=1; while(b) { if(b&1) { ans*=base; ans%=mod; } base*=base; base%=mod; b>>=1; } return ans; } signed main() { p=r();b=r();n=r(); int g=gcd(b,p); if(n%g) { cout<<"no solution"<<endl; return 0; } n/=g;p/=g;b/=g; int s=sqrt(p)+1; int now=1; for(int i=1;i<=s;i++)//b^i { now*=b; now%=p; if(m.find(now)==m.end())m[now]=i; } for(int i=0;i<=s;i++)//根號分塊 si+j { int tmp=pw(b,i*s,p); tmp=pw(tmp,p-2,p); int x=n*tmp; x%=p; if(m.find(x)!=m.end()) { cout<<i*s+m[x]; return 0; } } cout<<"no solution"; }