POJ 2417 Discrete Logging Baby-Step-Gaint-Step

题目大意:给出A,B,C,求A^x=B(mod C)的最小x的值。


思路:著名的BSGS算法。将C拆分成根号块,先对一个根号内的东西暴力插入一个Hash表中(别问我为什么不用map,因为这个题卡map。。。

另我们要求的x=i * m + j,原式可以写成A^(i * m) * A^j = B(mod C)。这是ax=b(mod c)的形式我们只需要枚举i,然后看有没有符合要求的j就可以了。


CODE:

#define _CRT_SECURE_NO_WARNINGS

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

long long A,B,C;

void EXGCD(long long a,long long b,long long &d,long long &x,long long &y)
{
	if(!b) {
		d = a,x = 1,y = 0;
		return ;
	}
	EXGCD(b,a % b,d,y,x);
	y -= x * (a / b);
}

long long Solve(long long a,long long b,long long c)	//ax = b(mod c)
{
	long long x = 0,y = 0,d = 0;
	EXGCD(a,c,d,x,y);
	return ((x % c) + c) * b % c;
}

long long QuickPower(long long x,long long y)
{
	long long re = 1;
	while(y) {
		if(y&1)	re = re * x % C;
		x = x * x % C;
		y >>= 1;
	}
	return re;
}

struct HashSet{
#define MO 23333
	int head[MO * 2 + 10],total;
	int next[MO * 2 + 10],f[MO * 2 + 10];
	long long val[MO * 2 + 10];

	void Reset() {
		memset(head,0,sizeof(head));
		total = 0;
	}
	void Insert(long long x,int _) {
		int temp = x % MO;
		for(int i = head[temp]; i; i = next[i])
			if(val[i] == x) {
				f[i] = min(f[i],_);
				return ;
			}
		next[++total] = head[temp];
		val[total] = x;
		f[total] = _;
		head[temp] = total;
	}
	int Find(long long x) {
		int temp = x % MO;
		for(int i = head[temp]; i; i = next[i])
			if(val[i] == x)
				return f[i];
		return -1;
	}
}G;

int main()
{
	while(scanf("%I64d%I64d%I64d",&C,&A,&B) != EOF) {
		G.Reset();
		long long temp = 1,m = ceil(sqrt((double)C));
		for(int i = 0; i < m; ++i) {
			G.Insert(temp,i);
			temp = temp * A % C;
		}
		bool find = false;
		for(int i = 0; i * m < C; ++i) {
			long long temp = Solve(QuickPower(A,i * m),B,C);
			if(G.Find(temp) != -1) {
				printf("%I64d\n",i * m + G.Find(temp));
				find = true;
				break;
			}
		}
		if(!find)	puts("no solution");
	}
	return 0;
}


你可能感兴趣的:(poj,BSGS)