【bzoj3122】[Sdoi2013]随机数生成器 BSGS

xi=axi+b
特判x1是否等于t
当a=0时,xi=b,直接判断t是否等于b
当a=1时,xi=x1+(i-1)*b=t,特判b是否等于0,i=(t-x1)*b^(-1)+1
当b=0时,xi=x1*a^(i-1)=t,如果x1或a=0,则判断t是否等于0,否则,BSGS
否则,
xi=axi-1+b
xi+b/(a-1)=axi-1+ab/(a-1)
xi+b/(a-1)=a(xi-1+b/(a-1))
xi+b/(a-1)=(x1+b/(a-1))*a^(i-1)
xi=(x1+b/(a-1))*a^(i-1)-b/(a-1)
可以看做a^y=z(mod p)的形式
z=(t+b*(a-1)^(-1))*(x1+b*(a-1)^(-1))^(-1)

y=i-1<=>i=y+1


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<map>

using namespace std;

long long a,b,x1,t,mod;
int T;
map<long long,int> mp;

long long power(long long x,long long y,long long mod)
{
	long long ans=1;
	while (y)
	{
		if (y&1) ans=ans*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return ans;
}

int BSGS(long long y,long long z,long long mod)
{
	if (y==0 && z==0) return 1;
	if (y==0 && z!=0) return -2;
	mp.clear();
	long long temp=z,p=power(y,mod-2,mod);
	int k=ceil(sqrt(mod));
	mp[z]=k+1;
	for (int i=1;i<k;i++)
	{
		temp=temp*p%mod;
		if (!mp[temp]) mp[temp]=i;
	}
	temp=1;p=power(y,k,mod);
	for (int i=0;i<k;i++,temp=temp*p%mod)
	{
		if (mp[temp])
		{
			if (mp[temp]==k+1) return i*k;
			else return i*k+mp[temp];
		}
	}
	return -2;
}

int main()
{
	scanf("%d",&T);
	while (T--)
	{
		scanf("%lld%lld%lld%lld%lld",&mod,&a,&b,&x1,&t);
		if (x1==t) {printf("1\n");continue;}
		if (a==0)
		{
			if (t==b) printf("2\n"); else printf("-1\n");
			continue;
		}
		if (a==1) 
		{
			if (b) printf("%d\n",((t-x1+mod)%mod)*power(b,mod-2,mod)%mod+1);
			else
			{
				if (t==x1) printf("1\n");
				else printf("-1\n");
			}
			continue;
		}
		long long tmp=power(a-1,mod-2,mod);
		printf("%d\n",BSGS(a,((t+b*tmp)%mod)*power((x1+b*tmp)%mod,mod-2,mod)%mod,mod)+1);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值