Discrete Logging
Description
Given a prime P, 2 <= P < 2
31, an integer B, 2 <= B < P, and an integer N, 1 <= N < P, compute the discrete logarithm of N, base B, modulo P. That is, find an integer L such that
BL == N (mod P) Input
Read several lines of input, each containing P,B,N separated by a space.
Output
For each line print the logarithm on a separate line. If there are several, print the smallest; if there is none, print "no solution".
Sample Input 5 2 1 5 2 2 5 2 3 5 2 4 5 3 1 5 3 2 5 3 3 5 3 4 5 4 1 5 4 2 5 4 3 5 4 4 12345701 2 1111111 1111111121 65537 1111111111 Sample Output 0 1 3 2 0 3 1 2 0 no solution no solution 1 9584351 462803587 Hint
The solution to this problem requires a well known result in number theory that is probably expected of you for Putnam but not ACM competitions. It is Fermat's theorem that states
B(P-1) == 1 (mod P) for any prime P and some other (fairly rare) numbers known as base-B pseudoprimes. A rarer subset of the base-B pseudoprimes, known as Carmichael numbers, are pseudoprimes for every base between 2 and P-1. A corollary to Fermat's theorem is that for any m B(-m) == B(P-1-m) (mod P) . Source
Waterloo Local 2002.01.26
|
裸的BSGS
b^L=b^k1*b^k2
已知b^k1 hash b^k2 复杂度O(sqrt(F)*hash(F)) hash(F)为哈希的复杂度
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<functional> #include<iostream> #include<cmath> #include<cctype> #include<ctime> using namespace std; #define For(i,n) for(int i=1;i<=n;i++) #define Fork(i,k,n) for(int i=k;i<=n;i++) #define Rep(i,n) for(int i=0;i<n;i++) #define ForD(i,n) for(int i=n;i;i--) #define RepD(i,n) for(int i=n;i>=0;i--) #define Forp(x) for(int p=pre[x];p;p=next[p]) #define Forpiter(x) for(int &p=iter[x];p;p=next[p]) #define Lson (x<<1) #define Rson ((x<<1)+1) #define MEM(a) memset(a,0,sizeof(a)); #define MEMI(a) memset(a,127,sizeof(a)); #define MEMi(a) memset(a,128,sizeof(a)); #define INF (2139062143) #define F (100000007) #define MAXN (1000000) typedef long long ll; ll mul(ll a,ll b){return (a*b)%F;} ll add(ll a,ll b){return (a+b)%F;} ll sub(ll a,ll b){return (a-b+(a-b)/F*F+F)%F;} void upd(ll &a,ll b){a=(a%F+b%F)%F;} char s[]="no solution\n"; class Math { public: ll gcd(ll a,ll b){if (!b) return a;return gcd(b,a%b);} ll abs(ll x){if (x>=0) return x;return -x;} ll exgcd(ll a,ll b,ll &x, ll &y) { if (!b) {x=1,y=0;return a;} ll g=exgcd(b,a%b,x,y); ll t=x;x=y;y=t-a/b*y; return g; } ll pow2(ll a,int b,ll p) { if (b==0) return 1; if (b==1) return a; ll c=pow2(a,b/2,p); c=c*c%p; if (b&1) c=c*a%p; return c; } ll Modp(ll a,ll b,ll p) { ll x,y; ll g=exgcd(a,p,x,y),d; if (b%g) {return -1;} d=b/g;x*=d,y*=d; x=(x+abs(x)/p*p+p)%p; return x; } int h[MAXN]; ll hnum[MAXN]; int hash(ll x) { int i=x%MAXN; while (h[i]&&hnum[i]!=x) i=(i+1)%MAXN; hnum[i]=x; return i; } ll babystep(ll a,ll b,int p) { MEM(h) MEM(hnum) int m=sqrt(p);while (m*m<p) m++; ll res=b,ans=-1; ll uni=pow2(a,m,p); if (!uni) if (!b) ans=1;else ans=-1; //特判 else { Rep(i,m+1) { int t=hash(res); h[t]=i+1; res=(res*a)%p; } res=uni; For(i,m+1) { int t=hash(res); if (h[t]) {ans=i*m-(h[t]-1);break;}else hnum[t]=0; res=res*uni%p; } } return ans; } }S; int main() { // freopen("poj2471.in","r",stdin); // freopen(".out","w",stdout); ll p,b,n; while(cin>>p>>b>>n) { ll ans=S.babystep(b,n,p); if (ans==-1) cout<<s; else cout<<ans<<endl; } return 0; }