bzoj 3122 随机数生成器 - BSGS

Description

Input

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

注意:P一定为质数

Output

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

Sample Input

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


Sample Output


1
3
-1

HINT

 

0<=a<=P-1,0<=b<=P-1,2<=P<=10^9

题目大意

  给定一个序列$X$的首项$x_{1}$,序列$X$满足递推关系$x_{n + 1} = (a\cdot x_{n} + b)\mod p$,其中这里的$mod$表示求余数。问序列中哪个数第一次为$t$,或者输出无解。

  显然递推关系对方程不是特别友好,所以考虑求序列的通项。

  由于这里用特征根的方法来求会很繁琐,所以直接展开:

$x_{n} = \left ( a\cdot x_{n - 1} + b \right ) \mod p$

$x_{n} = \left ( a^{2}\cdot x_{n - 2} + ab + b \right ) \mod p$

$x_{n} = \left ( a^{n - 1}\cdot x_{1} + a^{n-2}b + \cdots + ab + b \right ) \mod p$

  用等比数列求和公式得到:

$x_{n} = \left [ a^{n - 1}\cdot x_{1} + \frac{\left (a^{n - 1} - 1  \right )b}{a - 1}\right ] \mod p\ \ \ (a \neq 1)$

$x_{n} = \frac{a^{n - 1}\cdot x_{1}\left ( a - 1 \right ) + \left (a^{n - 1} - 1  \right )b}{a - 1} \mod p\ \ \ (a \neq 1)$

$x_{n} = \frac{a^{n - 1}\cdot\left [ x_{1}\left ( a - 1 \right ) + b  \right ]  - b}{a - 1} \mod p\ \ \ (a \neq 1)$

  然后再移项:

$a^{n - 1}\cdot\left [ x_{1}\left ( a - 1 \right ) + b  \right ] \equiv \left ( a - 1 \right )x_{n} + b \pmod{p}\ \ \ (a \neq 1)$

  BSGS解方程即可。

  继续考虑$a = 1$的情况,此时有:

$x_{n} \equiv x_{1} + \left ( n - 1 \right )b \pmod{p} \ \ \left ( a = 1 \right )$

  写成不定方程的形式:

$n\cdot b + k\cdot p = x_{n}+ b - x_{1}\ \ \left ( a = 1 \right )$

  直接扩欧算答案。

  注意一个细节,扩欧如果算出答案模$p$为0,那么应该输出$p$,因为这里求的是最小正余数。

  似乎$a = 0$的时候,要加点处理,不然扔进去的东西变成负数,BSGS也会出事情。干脆直接特判。

Code

  1 /**
  2  * bzoj
  3  * Problem#3122
  4  * Accepted
  5  * Time: 268ms
  6  * Memory: 2028k
  7  */
  8 #include <iostream>
  9 #include <cstring>
 10 #include <cstdio>
 11 #include <cmath>
 12 using namespace std;
 13 typedef bool boolean;
 14 
 15 typedef class HashMap {
 16     private:
 17         static const int M = 46666; 
 18     public:
 19         int ce;
 20         int h[M], key[M], val[M], next[M];
 21         
 22         HashMap() {    }
 23         
 24         void insert(int k, int v) {
 25             int ha = k % M;
 26             for (int i = h[ha]; ~i; i = next[i])
 27                 if (key[i] == k) {
 28                     val[i] = v;
 29                     return;
 30                 }
 31             ++ce, key[ce] = k, val[ce] = v, next[ce] = h[ha], h[ha] = ce;
 32         }
 33         
 34         int operator [] (int k) {
 35             int ha = k % M;
 36             for (int i = h[ha]; ~i; i = next[i])
 37                 if (key[i] == k)
 38                     return val[i];
 39             return -1;
 40         }
 41         
 42         void clear() {
 43             ce = -1;
 44             memset(h, -1, sizeof(h));
 45         }
 46 }HashMap; 
 47 
 48 
 49 int qpow(int a, int pos, int m) {
 50     int pa = a, rt = 1;
 51     for ( ; pos; pos >>= 1, pa = pa * 1ll * pa % m)
 52         if (pos & 1)
 53             rt = rt * 1ll * pa % m;
 54     return rt;
 55 }
 56 
 57 int gcd (int a, int b) {
 58     return (b) ? (gcd(b, a % b)) : (a);
 59 }
 60 
 61 void exgcd(int a, int b, int& d, int &x, int &y) {
 62     if (!b)
 63         d = a, x = 1, y = 0;
 64     else {
 65         exgcd(b, a % b, d, y, x);
 66         y -= (a / b) * x;
 67     }
 68 }
 69 
 70 int inv(int a, int n) {
 71     int d, x, y;
 72     exgcd(a, n, d, x, y);
 73     return (x < 0) ? (x + n) : (x);
 74 }
 75 
 76 int T;
 77 int p, a, b, x1, t;
 78 
 79 inline void init() {
 80     scanf("%d%d%d%d%d", &p, &a, &b, &x1, &t);
 81 }
 82 
 83 HashMap mp;
 84 inline int ind(int x, int a, int p, int pro) {
 85     mp.clear();
 86     int cs = sqrt(p - 1 + 0.5);
 87     int ainv = inv(x, p), iap = a * 1ll * qpow(ainv, cs - 1, p) % p;
 88     for (int i = cs - 1; ~i; i--, iap = iap * 1ll * x % p)
 89         mp.insert(iap, i);
 90     int cp = qpow(x, cs, p), pw = pro;
 91     for (int i = 0; i < p; i += cs, pw = pw * 1ll * cp % p)
 92         if (~mp[pw])
 93             return mp[pw] + i;
 94     return -2;
 95 }
 96 
 97 inline int solve1() {
 98     if (!b)    return (t == x1) ? (1) : (-1);
 99     int d, x, y, go = t + b - x1;
100     exgcd(b, p, d, x, y);
101     x = x * 1ll * go % p;
102     return (x <= 0) ? (x + p) : (x);
103 }
104 
105 inline void solve() {
106     if (a == 0)
107         printf("%d\n", (t == x1) ? (1) : ((b == t) ? (2) : (-1)));
108     else if (a == 1)
109         printf("%d\n", solve1());
110     else
111         printf("%d\n", ind(a, ((a - 1) * 1ll * t + b) % p, p, (x1 * 1ll * (a - 1) + b) % p) + 1);
112 }
113 
114 int main() {
115     scanf("%d", &T);
116     while (T--) {
117         init();
118         solve();
119     }
120     return 0;
121 }
posted @ 2018-02-27 20:37  阿波罗2003  阅读(...)  评论(... 编辑 收藏