省赛出原:随机数生成器,怎么敢的
前置芝士
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();
}
“亮,再不能临阵讨贼,悠悠苍天,何薄于我。”