P3306 [SDOI2013] 随机数生成器

本文介绍了一种利用Baby-Step Giant-Step (BSGS)算法结合扩展欧几里得算法(exgcd)解决特定高次同余方程的方法。通过分析线性递推数列的性质,将问题转化为求解高次同余方程,适用于多项式形式的数列,并给出了详细的算法步骤及代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Label

简单BSGS+简单exgcd

Description

给定整数a,b,x1,t(0≤a,b,x1,t<p,2<p≤109,p为质数)a,b,x_1,t(0\leq a,b,x_1,t<p,2<p\leq10^9,p为质数)a,b,x1,t(0a,b,x1,t<p,2<p109,p),每项取值范围为0∼p−10\sim p-10p1的数列{x}\{x\}{x}满足:xi+1≡axi+b(modp)x_{i+1}\equiv ax_i+b(modp)xi+1axi+b(modp),试求最小的iii使得xi≡t(modp)x_i\equiv t(modp)xit(modp),无解输出−1-11。每个数据点为多测(T≤50T\leq50T50)。

Solution

根据xxx的通项公式,利用迭代法我们可求得:
xn=an−1x1+b∑i=0n−2ai=an−1x1+b1−an−11−ax_n=a^{n-1}x_1+b\sum_{i=0}^{n-2}a^i=a^{n-1}x_1+b\frac{1-a^{n-1}}{1-a}xn=an1x1+bi=0n2ai=an1x1+b1a1an1

那么问题便可被转化为:求最小的nnn,使得
an−1x1+b1−an−11−a≡t(modp)a^{n-1}x_1+b\frac{1-a^{n-1}}{1-a}\equiv t(modp)an1x1+b1a1an1t(modp)

此为高次同余方程,经化简后,原式等价于
an−1≡t(a−1)+bx1(a−1)+b(modp)a^{n-1}\equiv \frac{t(a-1)+b}{x_1(a-1)+b}(modp)an1x1(a1)+bt(a1)+b(modp)

m=t(a−1)+bx1(a−1)+b=cdm=\frac{t(a-1)+b}{x_1(a-1)+b}=\frac{c}{d}m=x1(a1)+bt(a1)+b=dc由于ppp为质数,有:

1、我们可将同余号右端项换为其逆元,即令m=inv(m)=cdp−2m=inv(m)=cd^{p-2}m=inv(m)=cdp2

2、此高次同余方程可利用普通的BSGSBSGSBSGS来解。

最后注意:

1、当a=0a=0a=0时特判;

2、a=1a=1a=1时,具体来讲,此时原方程等价于xn=x1+(n−1)b≡t(modp)x_n=x_1+(n-1)b\equiv t(mod p)xn=x1+(n1)bt(modp),此为一阶线性同余方程,用exgcdexgcdexgcd解最小nnn即可。

Code

写题总结:

1、码力与程序流程、逻辑需要不断优化(比如下2);

2、多测时:所有的变量清空一定放到work函数的最前面;

3、考虑到且考虑清楚每一种特判的情况。

#include<cstdio>
#include<cmath>
#include<iostream>
#include<map>
#define ri register int
#define ll long long
using namespace std;

int Ttot;
ll B,X,T,aa,bb,xx,yy,xi,yi,g,a,b,p,t,ai=1,ans;
map<ll,int>hash;

ll Abs(ll x) {
	return((x>0)?(x):(-x));
}
ll Gcd(ll x,ll y) { 
	return ((y==0)?(x):Gcd(y,x%y));
}

void exgcd(ll aa,ll bb)
{
	if(bb==0)
	{ 
		xx=1; yy=0; 
		return;
	}
	exgcd(bb,aa%bb);
	xi=xx,yi=yy;
	xx=yi,yy=xi-(aa/bb)*yi;
}

ll power(ll x,ll y)
{
	if(y==0)	return 1%p;
	if(y==1)	return x%p;
	ll now=power(x,y/2);
	now=now*now%p;
	if(y&1)	now=now*x%p;
	return now;
}

void BSGS()
{
	t=sqrt(p);
	if(t*t<p)	++t;
	for(ll j=0;j<t;++j)
	{
		hash[b*ai%p]=j+1;
		ai=ai*a%p;
	}
	a=power(a,t); ai=1;
	for(ll i=0;i<=t;++i)
	{
		ll j=hash[ai];
		if(j>=1)
		{
			ans=i*t-(j-1);
			if(ans>0)	return;
		}
		ai=ai*a%p;
	}
}

void work()
{
	ans=-1; hash.clear();  ai=1;
	scanf("%lld%lld%lld%lld%lld",&p,&a,&B,&X,&T);
	if(X==T) { cout<<"1"<<'\n'; return; }
	if(a==0&&B==T) { cout<<"2"<<'\n'; return; }
	if(a==0&&B!=T) { cout<<"-1"<<'\n'; return; }
	if(a==1)
	{
		if(B==0) { cout<<"-1"<<'\n'; return; }
		g=Gcd(B,p);
		if((T-X)%g!=0) { cout<<"-1"<<'\n'; return; }
		exgcd(B,p);
		xx*=(T-X)/g;
		xx=(xx%Abs(p/g)+Abs(p/g))%Abs(p/g);
		cout<<xx+1<<'\n';
		return;
	}
	b=(((T*(a-1)%p+B%p)%p)*power((X*(a-1)%p+B%p)%p,p-2))%p;
	BSGS();
	if(ans>=0)	cout<<ans+1<<'\n';
	else	cout<<"-1"<<'\n';	
}

int main()
{
	scanf("%d",&Ttot);
	for(ri i=1;i<=Ttot;++i)	work();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值