吉林省赛 C.Random Number Generator(BSGS算法)

省赛出原:随机数生成器怎么敢的

前置芝士

BSGS算法: 在 复杂度下求解

假定你已经会了费马小定理,就可以知道:

所以其实 并不是无限大的,当 就会进入循环,所以我们只有考虑

如果从大到小遍历一遍,复杂度就是 ,依然无法过题。

我们考虑用一些 奇技淫巧 优化,通常对于一个 的算法我们有以下优化方式:

  • 通过二分、倍增等方法优化至 ,但此题没有单调性什么的,所以不考虑这种方法。

  • 通过分块思想优化至 ,我们考虑用这种。

我们设 ,那么 ,可得,同乘 可得

然后枚举所有 插入一个hash表;再枚举 ,看看hash表里有没有相等的。

复杂度直接降至

BSGS算法具体代码如下:

void BSGS()
{
	cin >> p >> b >> n;
	ll t = sqrt(p)+1;
	map<ll, ll> mp;
	for (ll j = 0; j <= t; j++) {
		ll tmp = n * qpow(b, j) % p;
		mp[tmp] = j;
	}
	
	for (ll i = 1; i <= t; i++) {
		ll tmp = qpow(b, t * i) % p;
		if (mp.count(tmp)) {
			cout << t * i - mp[tmp] << '\n';
			return;
		}
	}
	cout << "no solution\n";
}

解题过程

然后就是开始大力推式子,这里应该没什么难度,不过要记得等比公式(我记错了还好有队友提醒):

如果我们有一个等比数列 ,其中公比为 ,那么这个数列的前 项和为:

然后还要记得特判一下

题解代码:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>; 

ll a, b, x0, x, m;
ll qpow(ll x, ll y) {
	ll res = 1;
	while (y) {
		if (y & 1) res = (res * x) % m;
		x = x * x % m;
		y >>= 1;
	}
	return res;
}
void solve()
{
	cin >> a >> b >> m >> x0 >> x;
	//记得特判
	if (x0 == x) {
		cout << "YES\n";
		return;
	}
	if (a <= 1) {
		if (a == 0) {
			if (x0 == x || x == b) {
				cout << "YES\n";
			}
			else cout << "NO\n";
		}
		else {
			if (b == 0) cout << "NO\n";
			else cout << "YES\n";
		}
		return;
	}

	ll tmp = b * qpow(a - 1, m - 2)%m;
	tmp = (x + tmp) % m * qpow((x0 + tmp)%m, m - 2) % m;

	ll t = sqrt(m) + 1;

	set<ll> s;
	for (ll j = 0; j <= t; j++) {
		ll res = tmp * qpow(a, j) % m;
		s.insert(res);
	}
	for (ll i = 1; i <= t; i++) {
		ll res = qpow(a, t * i)%m;
		if (s.count(res)) {
			cout << "YES\n";
			return;
		}
	}
	cout << "NO\n";
}


signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int tt = 1;

	//cin >> tt;
	while (tt--)solve();
}
“亮,再不能临阵讨贼,悠悠苍天,何薄于我。”
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值