2021杭电多校1 1007/HDU 6956 Pass!

博客介绍了如何利用特征方程找到通项公式,并应用BSGS算法(Binary Search for Group Size)解决数论问题。通过一个随机数生成器的题目实例,展示了如何在O(sqrt(n))的时间复杂度内求解。代码实现中涉及了多项式取模逆元、欧几里得算法、快速幂等概念。

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

思路就是找规律发现递推公式,用递推公式求解通项公式,bsgs分奇偶求解可以看这篇博客https://www.cnblogs.com/xiaopangpangdehome/p/15042792.html
(有exbsgs和bsgs模板)
有一道类似的题:
随机数生成器(洛谷也有这个题目)
题目大意:
在这里插入图片描述

思路:利用特征方程求解通项公式,再用bsgs求解,时间复杂度是O(sqrt§),注意一些特殊情况。
在这里插入图片描述

代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+7;
const int mod=998244353;
const ll INF=0x3f3f3f3f3f3f3f3f;
ll hs[N], head[N], nexts[N], id[N], top;
void insert(ll x, ll y, ll mod) //mod传 N
{
	ll k = x % mod;
	hs[top] = x;
	id[top] = y;
	nexts[top] = head[k];
	head[k] = top++;
}
ll find(ll x, ll mod)
{
	ll k = x % mod;
	for (int i = head[k]; i != -1; i = nexts[i])
		if (hs[i] == x)
			return id[i];
	return -1;
}
ll qmi(ll m, ll k, ll p)
{
    ll res = 1 % p, t = m;
    while (k)
    {
        if (k&1) res = res * t % p;
        t = t * t % p;
        k >>= 1;
    }
    return res;
}
ll gcd(ll a, ll b)
{
	return b == 0 ? a : gcd(b, a % b);
}
ll BSGS(ll a, ll b, ll p, ll a1) //质数传1
{
	memset(head, -1, sizeof(head));
	top = 1;
	a %= p, b %= p;
	if (a1 == 1 && 1 % p == b % p)
		return 0;
	if (a == 0)
	{
		if (b == 0)
			return 1;
		else
			return -1;
	}
	//unordered_map<ll, ll> hash; //map  unordered_map 都试试
	ll k = sqrt(p) + 1;
	ll ak = 1;
	for (ll i = 0; i < k; ++i)
	{
		ll t = ak * b % p;
		insert(t, i, N);
		//hash[t] = i;
		ak = ak * a % p;
	}
	for (ll i = 0; i <= k; ++i)
	{
		/* if (hash.count(a1) && i * k - hash[a1] >= 0)
			return i * k - hash[a1]; */
		ll j = find(a1, N);
		if (j != -1 && i * k - j >= 0)
			return i * k - j;
		a1 = a1 * ak % p;
	}
	return -1;
}
ll exBSGS(ll a, ll b, ll p)
{
	a %= p, b %= p;
	if (b == 1 || p == 1)
		return 0;
	ll cnt = 0, a1 = 1;
	ll d = gcd(a, p);
	while (d > 1)
	{
		if (b % d)
			return -1;
		p /= d;
		b /= d;
		a1 = (a1 * a / d) % p;
		++cnt;
		if (b == a1)
			return cnt;
		d = gcd(a, p);
	}
	ll res = BSGS(a, b, p, a1);
	if (res == -1)
		return -1;
	else
		return res + cnt;
}
int main()
{
    ll t;
    scanf("%lld",&t);
    while(t--)
    {
    	ll p,a,b,x1,t;
    	scanf("%lld%lld%lld%lld%lld",&p,&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)
    	{
    	    t=((t-x1)%p+p)%p;
    	    if(t%gcd(b,p)!=0)
    	    {
    	        printf("-1\n");
    	        continue;
    	    }
    	    ll temp=qmi(b,p-2,p);
    	    ll ans=(t*temp)%p+1;
    	    if(ans==p)
    	    {
    	        printf("%lld\n",ans);
    	        continue;
    	    }
    	    ans=ans%p;
    	    printf("%lld\n",ans);
    	    continue;
    	}
    	ll temp=qmi(a-1,p-2,p);
    	ll up=(t+b*temp)%p;
    	ll down=(x1+b*temp)%p;
    	down=qmi(down,p-2,p);
    	ll bb=(up*down)%p;
    	//printf("%lld %lld %lld\n",a,bb,p);
    	ll ans=BSGS(a,bb,p,1);
    	if(ans!=-1) printf("%lld\n",ans+1);
    	else printf("-1\n");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值