题目描述:
最近小 W 准备读一本新书,这本书一共有 (p) 页,页码范围为 (0 sim p-1)。
小 W 很忙,所以每天只能读一页书。为了使事情有趣一些,他打算使用 NOI2012 上学习的线性同余法生成一个序列,来决定每天具体读哪一页。
我们用 (x_i) 来表示通过这种方法生成出来的第 (i) 个数,也即小 W 第 (i) 天会读哪一页。这个方法需要设置 (3) 个参数 (a,b,x_1),满足 (0leq a,b,x_1lt p),且 (a,b,x_1) 都是整数。按照下面的公式生成出来一系列的整数:
$x_{i+1} equiv a imes x_i+b pmod p $
其中 ( mod) 表示取余操作。
但是这种方法可能导致某两天读的页码一样。
小 W 要读这本书的第 (t) 页,所以他想知道最早在哪一天能读到第 (t) 页,或者指出他永远不会读到第 (t) 页。
数据范围:(1leq Tleq 50), (0 leq a, b, x_1, t lt p), (2 leq p leq 10^9), (p) 为质数。
solution
我们尝试打一下表,找找规律:
(x_2 = ax_1 + b)
(x_3 = a^2x_1 + ab + b)
(x_4 = a^3x_1 + a^2b + ab + b)
(x_5 = a^4x_1 + a^3b + a^2b + ab + b)
(x_6 = a^5x_1 + a^4b + a^3b + a^2b + ab + b)
不难发现: (x_n = a^{n-1}x_1 + displaystylesum_{i=0}^{n-2} a^ib, (x gt 1))
根据等比数列的求和公式则有: (displaystylesum_{i=0}^{n-2} a^ib = b{1-a^{n-1}over 1-a}) 。
带入可得:(x_n = a^{n-1}x_1 + {bover 1-a} (1-a^{n-1})) 。
化简一下:
(x_n = a^{n-1}x_1 + {bover 1-a} (1-a^{n-1}))
(x_n = a^{n-1}x_1 - a^{n-1}{bover 1-a} + {bover 1-a})
设 (B = {bover 1-a}), 则原式可以化为:
(x_n = (x_1-B) a^{n-1} + B)
(ecause x_n equiv t)
( herefore (x_1-B) a^{n-1} + Bequiv t) 。
( herefore (x_1-B)a^{n-1} equiv t-B pmod p)
( herefore a^{n-1} equiv {t-Bover x_1-B} pmod p)
用 (BSGS) 算法求解即可。
几个需要特判的点 (被卡到吐):
- 当 (x_1 = t) 的时候,直接输出 (1)
- 当 (a = 0) 的时候,如果 (t = b) 输出 (1) , 反之输出 (-1)
- 当 (a = 1) 的时候, 如果 (b = 0) 且 (x eq t) 输出 (-1), 否则输出 ((t-x) over b)
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;
#define int long long
int T,a,b,p,x,t;
inline int read()
{
int s = 0, w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
return s * w;
}
int ksm(int a,int b)
{
int res = 1;
for(; b; b >>= 1)
{
if(b & 1) res = res * a % p;
a = a * a % p;
}
return res;
}
int BSGS(int a,int b,int p)
{
map<int,int> hash;
int m = sqrt(p) + 1;
for(int i = 0; i <= m; i++)
{
int val = b * ksm(a,i) % p;
hash[val] = i;
}
a = ksm(a,m);
for(int i = 0; i <= m; i++)
{
int val = ksm(a,i);
int j = hash.find(val) == hash.end() ? -1 : hash[val];
if(j > 0 && i * m - j > 0) return i * m - j;
}
return -1;
}
signed main()
{
T = read();
while(T--)
{
p = read(); a = read(); b = read(); x = read(); t = read();
if(x == t){printf("%d
",1); continue;}
if(a == 0)
{
if(t == x) printf("%d
",1);
else if(t == b) printf("%d
",2);
else printf("%d
",-1);
continue;
}
if(a == 1)
{
if(b == 0 && x != t) printf("%d
",-1);
else printf("%lld
",(((t-x+p)%p)*ksm(b,p-2)%p)+1);
continue;
}
int tmp = (1 - a + p) % p;
int inv = ksm(tmp,p-2);
t = (t - (b * inv % p) + p) % p;
x = (x - (b * inv % p) + p) % p;
t = t * ksm(x,p-2) % p;
int ans = BSGS(a,t,p);
if(ans == -1) printf("%d
",-1);
else printf("%lld
",ans+1);
}
return 0;