A^x = D (mod P)

0 <= x <= M, here M is a given integer. 

1 <= A, P < 2^31, 0 <= D < P, 1 <= M < 2^63

----------------------------------------------------------

裸拓展baby step giant step

先转成非拓展版,然后如果在转的过程中就出解了,则return 1,否则就找出=D的起点和循环节长度,然后直接求解。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
const int Hash_MOD = 1000003;
typedef long long LL;
typedef unsigned long long ULL;
LL times;
struct link
{
	LL link;
	int val,next;
}es[100000];
struct triple
{
	LL x,y,g;
	triple(const LL _x = 0,const LL _y = 0,const LL _g = 0):
		x(_x),y(_y),g(_g){}
};
int H[Hash_MOD * 2],ec;
triple exgcd(const LL a,const LL b)
{
	if (!b) return triple(1,0,a);
	const triple last(exgcd(b,a%b));
	return triple(last.y,last.x - a / b * last.y,last.g);
}
LL rem_equ(const LL a,const LL b,const LL c)
{
	//ax == c (mod b)
	//ax mod b == c
	const triple tmp(exgcd(a,b));
	const LL MOD = (b / tmp.g);
	return ((tmp.x * (c / tmp.g) % MOD) + MOD) % MOD;
}
LL find(const LL x)
{
	for (int i = H[x%Hash_MOD]; i; i = es[i].next)
		if (es[i].link == x) return es[i].val;
	return -1;
}
void insert(LL x,const LL v)
{
	if (find(x) != -1) return;
	const LL key = x % Hash_MOD;
	es[++ec].next = H[key];
	H[key] = ec;
	es[ec].link = x;
	es[ec].val = v;
}
LL BSGS(LL A,LL P,LL D)
{
	LL AA = 1 % P,x = 1 % P,MOD = P,DD = D,m = static_cast<LL>(std::ceil(std::sqrt((double)P)));
	times = 0;
	for (triple tmp; (tmp = exgcd(A,P)).g != 1; ) {
		if (x == DD) return times++;
		if (D % tmp.g) return -1;
		P /= tmp.g;
		D /= tmp.g;
		(AA *= A / tmp.g) %= P;
		++times;
		(x *= A) %= MOD;
	}
	A %= P;
	ec = 0;
	memset(H,0,sizeof H);
	LL tmp = 1 % P;
	for (int i = 0; i < m; ++i,(tmp *= A) %= P)	
		insert(tmp,i);
	x = 1 % P;
	for (LL i = 0; i < m; ++i,(x *= tmp) %= P) {
		const int j = find(rem_equ(AA*x%P,P,D));
		if (j != -1) return i * m + j + times;
	}
	return -1;
}
LL getphi(LL x)
{
	LL res = 1;
	for (LL i = 2; i * i <= x; ++i)
		if (x % i == 0) {
			x /= i;
			res *= i - 1;
			while (x % i == 0) x /= i,res *= i;
		}
	if (x > 1) res *= x - 1;
	return res;
}
LL power(LL a,LL k,LL MOD)
{
	//a ^ k % MOD
	LL res = 1 % MOD;
	for (; k; k/=2,(a *= a) %= MOD)
		if (k & 1) (res *= a) %= MOD;
	return res;
}
LL calc_len(const LL start,const LL A,const LL P,const LL D)
{
	//A ^ (start + *this) == A ^ start == D (mod P)
	LL phi = getphi(P),res = phi;
	for (LL i = 2; i * i <= phi; ++i) {
		for (; phi % i == 0; phi /= i);
		for (; res % i == 0 && power(A,start + res/i,P) == D; res /= i);
	}
	if (phi > 1)
		for (; res % phi == 0 && power(A,start + res/phi,P) == D; res /= phi);
	return res;
}
ULL work(const LL A,const LL P,const LL D,const ULL M)
{
	LL start = BSGS(A,P,D);
	//printf("%lld\n",start);
	if (start == -1 || start > M) return 0;
	else if (start < times) return 1;
	// LL phi=getphi(P);
	// if (power(A,start + phi,P) != D) return 1;
	ULL len = calc_len(start,A,P,D);
	return (M - start) / len + 1;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("3254.in","r",stdin);
	freopen("3254.out","w",stdout);
#endif
	LL A,P,D;
	ULL M;
	while (~scanf("%lld%lld%lld%llu",&A,&P,&D,&M))
		printf("%llu\n",work(A%P,P,D,M));
}

 posted on 2013-10-21 16:35  Lazycal  阅读(365)  评论(0编辑  收藏  举报