bzoj3122【同余方程】【BSGS】

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
typedef long long LL;
inline int read()
{
	int x=0;bool f=0;char c=getchar();
	for (;c<'0'||c>'9';c=getchar()) f=c=='-'?1:0;
	for (;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
	return f?-x:x;
}

LL qpw(LL a,LL k,LL p)
{
	LL rec=1;
	while (k)
	{
		if (k&1) rec=(rec*a)%p;
		a=(a*a)%p;k>>=1;
	}
	return rec;
}

LL sqr,pw[100010];
map<LL,LL> mp;
map<LL,LL> :: iterator it;
void bsgs_init(LL p,LL g)
{
	mp.clear();
	sqr=(LL)sqrt(p-1)+1;
	for (int i=0;i<sqr;i++) pw[i]=qpw(g,p-1-i,p);
	LL gq=qpw(g,sqr,p),rec=1;
	for (int i=0;i<p-1;i+=sqr) 
		mp.insert(make_pair(rec,i)),rec=rec*gq%p; 
}

LL bsgs(LL a,LL p,LL g)
{
	for (int i=0;i<sqr;i++)
	{
		it=mp.find(a*pw[i]%p);
		if (it!=mp.end()) return it->second+i;
	}
}

LL ka,kb,kg;
void exgcd(LL a,LL b)
{
	if (!b) {ka=1,kb=0,kg=a;return;}
	exgcd(b,a%b);
	LL rec = ka ; ka = kb ; kb = rec - ( a / b ) * kb ;
}

LL solve(LL a,LL b,LL p)
{
	exgcd(a,p);
	if (b%kg) return -2;
	p/=kg;
	return (b*ka/kg%p+p)%p;
}

int main()
{
	for (int cas=read();cas--;)
	{
		LL p=read(),a=read(),b=read(),x0=read(),x=read(),g,ar,c;
		if (x0==x) {puts("1");continue;}
		if (!a) {puts(b==x?"2":"-1");continue;}
		if (a==1)
			{printf("%lld\n",solve(b,(x-x0+p)%p,p)+1);continue;}
		ar = qpw(a,p-2,p);
		c = b*ar%p*qpw((1-ar+p)%p,p-2,p)%p;
		x0 = ( x0 + c ) % p ; x = ( x + c ) % p ;
		if (!x0 && !x) {puts("1");continue;}
		else if (!x0 || !x) {puts("-1");continue;}
		x=x*qpw(x0,p-2,p)%p;
		for (g=2;g<p;g++)
		{
			bool ok=1;
			for (LL i=2;i*i<=p-1&&ok;i++) if ((p-1)%i==0)
				if (qpw(g,i,p)==1||qpw(g,(p-1)/i,p)==1) ok=0;
			if (ok) break;
		}
		if (p==2) g=1;
		bsgs_init(p,g);
		x = bsgs(x,p,g) ; a = bsgs(a,p,g);
		printf("%lld\n",solve(a,x,p-1)+1);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值