POJ 2417/BZOJ 3239(Discrete Logging-BSGS)[Template:数论]

Discrete Logging
Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 4236 Accepted: 1948

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



裸的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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值