AT_abc270_g [ABC270G] Sequence in mod P 题解

题目传送门

前置知识

大步小步算法

解法

  • 递推式为 \(x_{n}=(ax_{n-1}+b) \bmod p\),发现可以统一消去 \(\bmod p\) ,只在最后参与计算。以下过程省去模运算。
  • \(x_{0}=t\) 时,则 \(n=0\) 即为所求。
  • \(a=0,x_{0} \ne t\) 时,递推式转化为 \(x_{n}=b \bmod p\) 。若 \(b=t\) ,则 \(n=1\) 即为所求;否则无解。
  • \(a \ne 0,x_{0} \ne t\) 时,设 \(x_{n}+c=a(x_{n-1}+c)\)
    • \(a=1\) 时,递推式转化为 \(\begin{aligned} x_{n}&=x_{n-1}+b \\ &=x_{n-2}+2b \\ &=x_{n-3}+3b \\ &= \dots \\ &=x_{0}+nb \end{aligned}\),将 \(x_{n}=t\) 代入得 \(t=(x_{0}+nb) \bmod p\),移项得 \(nb \equiv (t-x_{0}) \pmod {p}\)。当 \(\gcd(b,p)|(t-x_{0})\) 时,移项得 \(n \equiv \dfrac{t-x_{0}}{b} \pmod {p}\),解得 \(n \equiv \dfrac{t-x_{0}}{b} \pmod {p}\);否则无解。
    • \(a \ne 1\) 时,解得 \(c=\dfrac{b}{a-1}\) 并和 \(x_{n}=t\) 一起代入原式得 \(\begin{aligned} t+\dfrac{b}{a-1}&=a(x_{n-1}+\dfrac{b}{a-1}) \\ &=a^{2}(x_{n-2}+\dfrac{b}{a-1}) \\ &=a^{3}(x_{n-3}+\dfrac{b}{a-1}) \\ &= \dots \\ &=a^{n}(x_{0}+\dfrac{b}{a-1}) \end{aligned}\) 。当 \(\gcd(x_{0}+\dfrac{b}{a-1},p)|(t+\dfrac{b}{a-1})\) 时,移项得 \(a^{n} \equiv \dfrac{t+\dfrac{b}{a-1}}{x_{0}+\dfrac{b}{a-1}} \pmod {p}\) ,跑遍 BSGS 求解即可;否则无解。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define ull unsigned long long
#define sort stable_sort 
#define endl '\n'
ll qpow(ll a,ll b,ll p)
{
	ll ans=1;
	while(b>0)
	{
		if(b&1)
		{
			ans=ans*a%p;
		}
		b>>=1;
		a=a*a%p;
	}
	return ans;
}
ll gcd(ll a,ll b)
{
	return b?gcd(b,a%b):a;
}
ll bsgs(ll a,ll b,ll p)
{
	if(1%p==b%p)
    {
        return 0;
    }
    else
    {
        map<ll,ll>vis;
        ll k=sqrt(p)+1,i,sum;
        for(i=0;i<=k-1;i++)
        {
            vis[b*qpow(a,i,p)%p]=i;
        }
        a=qpow(a,k,p);
		for(i=0;i<=k;i++)
		{
			sum=qpow(a,i,p);
			if(vis.find(sum)!=vis.end())
			{
				if(i*k-vis[sum]>=0)
				{
					return i*k-vis[sum];
				}
			}
		}
		return -1;
    }
}
int main()
{
	ll t,p,a,b,x0,day,ans,sum,i;
	cin>>t;
	for(i=1;i<=t;i++)
	{
		cin>>p>>a>>b>>x0>>day;
		if(x0==day)
		{
			cout<<0<<endl;
		}
		else
		{
			if(a==0)
			{
				cout<<((b==day)?1:-1)<<endl;
			}
			else
			{
				if(a==1)
				{
					if((day-x0)%gcd(b,p)==0)
					{
						cout<<qpow(b,p-2,p)*(day-x0+p)%p<<endl;
					}
					else
					{
						cout<<-1<<endl;
					}
				}
				else
				{
					sum=qpow(a-1,p-2,p)*b%p;
					if((day+sum)%gcd(x0+sum,p)==0)
					{
						ans=bsgs(a,((day+sum)%p)*qpow(x0+sum,p-2,p)%p,p);
						cout<<ans<<endl;
					}
					else
					{
						cout<<-1<<endl;
					}
				}
			}
		}
	}
	return 0;
}

后记

多倍经验:P3306 | Gym103486C

posted @ 2024-02-07 19:31  hzoi_Shadow  阅读(8)  评论(0编辑  收藏  举报
扩大
缩小