「Luogu3306」[SDOI2013]随机数生成器

「Luogu3306」[SDOI2013]随机数生成器

problem

Solution

我们来回忆一下数列递推公式求通项的方法

(Y_i=X_i+frac{b}{a-1}),则有

[Y_i=aY_{i-1}Rightarrow Y_i=a^{i-1}Y_1 ]

于是题目转化为求解方程

[t+frac b{a-1}equiv a^{x-1}(X_1+frac b{a-1})pmod p ]

[Rightarrow a^{x-1}equivfrac{t+frac b{a-1}}{X_1+frac b{a-1}}pmod p ]

好的,这个东西我们只要用BSGS就可以了

End?


几个细节:

(X_1=t)时,直接输出(1)

(a=0)时,输出若(b=t)则输出(2),否则无解,(X_1=t)的情况已经特判

(a=1)时,方程实际上为

[(x-1)bequiv t-X_1pmod p ]

根据裴蜀定理判掉无解,然后直接算(x-1)即可

需要注意的是如果(frac{t-X_1} b=p),则不需要取模直接输出

True End

Code

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <map>
#define mp(x,y) (make_pair((x),(y)))
#define inv(x) (fastpow((x),p-2))
using namespace std;
typedef long long ll;

template <typename T>void read(T &t)
{
	t=0;int f=0;char c=getchar();
	while(!isdigit(c)){f|=c=='-';c=getchar();}
	while(isdigit(c)){t=t*10+c-'0';c=getchar();}
	if(f)t=-t;
}

int T;

ll p,a,b,X1,t;
ll m;

ll fastpow(ll a,ll b)
{
	ll re=1,base=a;
	while(b)
	{
		if(b&1)
			re=re*base%p;
		base=base*base%p;
		b>>=1;
	}
	return re;
}

map<ll,ll> rec;
void Pre()
{
	rec.clear();
	ll tmp=1;
	for(register int i=0;i<m;++i,tmp=tmp*a%p)
		rec.insert(mp(tmp,i));
}

ll BSGS()
{
	ll iatm=inv(fastpow(a,m)),tmp=1;
	for(register int i=0;i<m;++i,tmp=tmp*iatm%p)
		if(rec.find(b*tmp%p)!=rec.end())
			return i*m+rec[b*tmp%p];
	return -2;
}

ll gcd(ll a,ll b)
{
	return b?gcd(b,a%b):a;
}

int main()
{
	read(T);
	while(T--)
	{
		read(p),read(a),read(b),read(X1),read(t);
		if(X1==t)
		{
			puts("1");
			continue;
		}
		if(a==1)
		{
			t=(t-X1+p)%p;
			if(t%gcd(b,p))
				puts("-1");
			else
				printf("%lld
",t*inv(b)+1==p?p:(t*inv(b)+1)%p);
			continue;
		}
		if(a==0)
		{
			printf("%lld
",b==t?2:-1ll);
			continue;
		}
		b=b*inv(a-1)%p;
		b=(t+b)*inv(X1+b)%p;
		m=ceil(sqrt(p));
		Pre();
		printf("%lld
",BSGS()+1);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/lizbaka/p/10656151.html