题目背景
小 (W) 喜欢读书,尤其喜欢读《约翰克里斯朵夫》。
题目描述
最近小 (W) 准备读一本新书,这本书一共有 (p) 页,页码范围为 (0 sim p-1)。
小 (W) 很忙,所以每天只能读一页书。为了使事情有趣一些,他打算使用 (NOI2012) 上学习的线性同余法生成一个序列,来决定每天具体读哪一页。
我们用 (x_i) 来表示通过这种方法生成出来的第 ii 个数,也即小 W 第 ii 天会读哪一页。这个方法需要设置 (3) 个参数 (a,b,x_1) ,满足 (0leq a,b,x_1lt p0),且 (a,b,x_1) 都是整数。按照下面的公式生成出来一系列的整数:
(x_{i+1} equiv a imes x_i+b pmod p)
其中 (mod) 表示取余操作。
但是这种方法可能导致某两天读的页码一样。
小 (W) 要读这本书的第 (t) 页,所以他想知道最早在哪一天能读到第 (t) 页,或者指出他永远不会读到第 (t) 页。
输入格式
本题单测试点内有多组测试数据。
第一行是一个整数 (T) ,表示测试数据组数。
接下来T行,每行有五个整数 (p, a, b, x_1, t) ,表示一组数据。
输出格式
对于每组数据,输出一行一个整数表示他最早读到第 (t) 页是哪一天。如果他永远不会读到第 (t) 页,输出 (-1)。
输入输出样例
输入 #1
3
7 1 1 3 3
7 2 2 2 0
7 2 2 2 1
输出 #1
1
3
-1
说明/提示
数据规模与约定
对于全部的测试点,保证:
- (1 leq T leq 50)。
- (0 leq a, b, x_1, t lt p,2 leq p leq 10^9)。
- (p) 为质数。
题解
已知 (a,b,x1,t,p) ,先列出前几项的公式
[x1 = x_1 \
x2 = ax_1+b\
x3 = a^2x_1+ab+b \
x4 = a^3x_1+a^2b + ab + b\
\
x_n = a^{n-1}x_1 + b(1+a+...+a^{n-1}) \
x_n = a^{n-1}x_1 + b(frac{a^{n-1}-1}{a-1}) \
a^{n-1} = frac{(a-1)t+b}{b+x_1(a-1)}
]
因为 (p) 是质数,之后使用 (BSGS) 算法进行求解。
上式中,(a) 不能等于 (1) ,对于 (a=1) ,存在
[x1 = x_1 \
x2 = x_1+b\
x3 = x_1+2b \
x4 = x_1+3b\
\
x_n = x_1+(n-1)b \
b=frac{x_n-x_1}{n-1}
]
注意
- 需要进行 (a = 0) 的所有特殊状态
- 如果 (x_1=t) 直接输出 (1)
代码
#include <map>
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
inline ll multi(ll a,ll b,ll mod){
ll ret=0;
if(b<0){
a=-a;b=-b;
}
while(b){
if(b&1)ret=(ret+a)%mod;
b>>=1;
a=(a+a)%mod;
}
return (ret%mod+mod)%mod;
}
inline ll pow(ll a,ll b,ll mod){
ll ret=1;
while(b){
if(b&1)ret=multi(ret,a,mod);
b>>=1;
a=multi(a,a,mod);
}
return (ret%mod+mod)%mod;
}
inline ll BSGS(ll a,ll b,ll m){
ll k=ceil(sqrt(m))+1;
map<ll,ll>M;
M.clear();
for(int i=0;i<=k;++i){
M[b]=i;
b=multi(b,a,m);
}
a=pow(a,k,m);
ll ret=a;
for(int i=1;i<=k;++i){
if(M.count(ret)){
return i*k-M[ret];
}
ret=multi(ret,a,m);
}
return -1;// 无解
}
int main(){
int _;
scanf("%d",&_);
while(_--){
ll p,a,b,x1,t;
scanf("%lld%lld%lld%lld%lld",&p,&a,&b,&x1,&t);
if(x1==t){
printf("1
");
continue;
}
if(a==1){
if(b==0){
if(x1==t)printf("1
");
else printf("-1
");
}
else{
printf("%lld
",(((t-x1)%p+p)%p*pow(b,p-2,p))%p+1);
}
continue;
}
if(a==0){
if(x1==t){
printf("1
");
}
else{
if(t==b){
printf("2
");
}
else printf("-1
");
}
continue;
}
ll aa=a%p;
ll ss=pow(((a-1)*x1+b)%p,p-2,p);
ll bb=((((a-1)*t+b)%p*ss)%p+p)%p;
ll pp=p;
ll k=BSGS(aa,bb,pp);
if(k==-1)printf("-1
");
else printf("%lld
",(k+1));
}
return 0;
}