列表

详情


NC20362. [SDOI2013]随机数生成器

描述

小W喜欢读书,尤其喜欢读《约翰克里斯朵夫》。最近小W准备读一本新书,这本书一共有P页,页码范围为0P1

小W很忙,所以每天只能读一页书。为了使事情有趣一些,他打算使用NOI2012上学习的线性同余法生成一个序列,来决定每天具体读哪一页。

我们用Xi来表示通过这种方法生成出来的第i个数,也即小Wi天会读哪一页。这个方法需要设置3个参数a,b,X1,满足0a,b,X1p1,且a,b,X1都是整数。按照下面的公式生成出来一系列的整数:Xi+1aXi+b(mod p)其中mod表示取余操作。

但是这种方法可能导致某两天读的页码一样。

小W要读这本书的第t页,所以他想知道最早在哪一天能读到第t页,或者指出他永远不会读到第t页。

输入描述

输入含有多组数据,第一行一个正整数T,表示这个测试点内的数据组数。    
接下来T行,每行有五个整数p,a,b,X1,t,表示一组数据。保证X1和t都是合法的页码。 
注意:P一定为质数

输出描述

共T行,每行一个整数表示他最早读到第t页是哪一天。如果他永远不会读到第t页,输出-1。

示例1

输入:

3 
7  1 1 3 3
7  2 2 2 0
7  2 2 2 1

输出:

1
3
-1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 379ms, 内存消耗: 2164K, 提交时间: 2023-04-04 18:02:56

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
 
ll T, p, a, b, x1, t, ans;
 
inline ll qpow(ll x, ll n, ll mod, ll res = 1LL) {
    for ( ; n; n >>= 1, x = x * x % mod) !(n & 1) ?: res = res * x % mod;
    return res;
}
 
map<ll, ll> bs;
inline ll bsgs(ll a, ll b, ll c) {
    ll m = sqrt(c) + 1; bs.clear();
    for (ll k = 0, t = b; k <= m; k ++, t = t * a % c) bs[t] = k;
    for (ll x = 1, t = qpow(a, m, c), base = t; x <= m; x ++, t = t * base % c)
        if (bs.count(t)) return ((x * m - bs[t]) % c + c) % c;
    return -2;
}
 
signed main() {
    scanf("%lld", &T);
    while (T--) {
        scanf("%lld%lld%lld%lld%lld", &p, &a, &b, &x1, &t);
        if (t == x1) { puts("1"); continue; }
        if (a == 0) { puts( b == t ? "2" : "-1" ); continue; }
        if (a == 1) { printf("%lld\n", b == 0 ? -1 : qpow(b, p - 2, p) * ((t - x1) % p + p) % p + 1); continue; }
        printf("%lld\n", bsgs(a, (t * (a - 1) + b) % p * qpow((x1 * (a - 1) + b) % p, p - 2, p) % p, p) + 1);
    }
    return 0;
}

C++ 解法, 执行用时: 198ms, 内存消耗: 2184K, 提交时间: 2021-08-03 10:19:23

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

ll T, p, a, b, x1, t, ans;

inline ll qpow(ll x, ll n, ll mod, ll res = 1LL) {
    for ( ; n; n >>= 1, x = x * x % mod) !(n & 1) ?: res = res * x % mod;
    return res;
}

map<ll, ll> bs;
inline ll bsgs(ll a, ll b, ll c) {
    ll m = sqrt(c) + 1; bs.clear();
	for (ll k = 0, t = b; k <= m; k ++, t = t * a % c) bs[t] = k;
	for (ll x = 1, t = qpow(a, m, c), base = t; x <= m; x ++, t = t * base % c) 
		if (bs.count(t)) return ((x * m - bs[t]) % c + c) % c;
	return -2;
} 

signed main() {
    scanf("%lld", &T);
    while (T--) {
        scanf("%lld%lld%lld%lld%lld", &p, &a, &b, &x1, &t);
        if (t == x1) { puts("1"); continue; } 
        if (a == 0) { puts( b == t ? "2" : "-1" ); continue; }
        if (a == 1) { printf("%lld\n", b == 0 ? -1 : qpow(b, p - 2, p) * ((t - x1) % p + p) % p + 1); continue; } 
        printf("%lld\n", bsgs(a, (t * (a - 1) + b) % p * qpow((x1 * (a - 1) + b) % p, p - 2, p) % p, p) + 1);
    }
    return 0;
}

上一题