【洛谷 P3306】[SDOI2013]随机数生成器

题目链接

怎么这么多随机数生成器

题意见原题。
很容易想到\(BSGS\)算法,但是递推式是\(X_{i+1}=(aX_i+b)\mod p\),这显然不是一个等比数列。
但是可以用矩阵乘法来求出第\(i\)项,所以好像可以用\(BSGS\)套矩阵乘法?但是总要把那个常数项除过来吧,矩阵除法是什么鬼?
无奈只好放弃去看题解。
看完之后,哎,我太蒻了。
\[X_{i+1}=(aX_i+b)\mod p\]
\[X_{i+1}=a(X_i+\frac{b}{a})\mod p\]
\[X_{i+1}=(aX_i+\frac{ab}{a})\mod p\]
\[X_{i+1}=(aX_i+\frac{(a-1)b}{a-1})\mod p\]
\[X_{i+1}+\frac{b}{a-1}=(aX_i+\frac{ab}{a-1})\mod p\]
\[X_{i+1}+\frac{b}{a-1}=a(X_i+\frac{b}{a-1})\mod p\]
然后,你发现了什么?
没错,式子两边都有一个\(X+\frac{b}{a-1}\)
把上面这个式子的左边再乘一个\(a\)就能得到\(X_{i+2}+\frac{b}{a-1}\)
于是就有
\[X_n+\frac{b}{a-1}=a^{n-1}(X_1+\frac{b}{a-1})\mod p\]
\[\frac{X_n+\frac{b}{a-1}}{X_1+\frac{b}{a-1}}\equiv a^{n-1}\pmod p\]
左边的都是已知的,对左边有理数取余,然后就可以\(BSGS\)了,不会\(BSGS\)的戳这里
另外对\(a=0,1\)或者\(X_1=t\)要特判一下

#include <cstdio>
#include <map>
#include <cmath>
#include <cstdlib>
#define ll long long
using namespace std;
int fast_pow(int n, int k, int p){  //n^k%p
    int ans = 1;
    while(k){
      if(k & 1) ans = (long long)ans * n % p;
      n = (long long)n * n % p;
      k >>= 1;
    }
    return ans;
}
int BSGS(int a, int b, int p){   //a^x≡b(mod p)
    map <int, int> hash; hash.clear();
    int t = ceil(sqrt(p));
    for(int i = 0; i < t; ++i){
       int val = (long long)b * fast_pow(a, i, p) % p;
       hash[val] = i;
    }
    a = fast_pow(a, t, p);
    if(!a) return !b ? 1 : -1;
    for(int i = 0; i <= t; ++i){
       int j = fast_pow(a, i, p);
       int k = hash.find(j) == hash.end() ? -1 : hash[j];
       if(k >= 0 && (i * t - k) >= 0) return i * t - k;
    }
    return -1;
}
void exgcd(int a, int b, int &x, int &y){
    if(!b){
      x = 1; y = 0;
      return;
    }
    exgcd(b, a % b, x, y);
    int z = x; x = y; y = z - (a / b) * y;
}
int T;
int p, a, b, x, t;
int X, Y;
int main(){
    scanf("%d", &T);
    while(T--){
      scanf("%d%d%d%d%d", &p, &a, &b, &x, &t);
      if(x == t) { printf("1\n"); continue; }
      if(!a){
        if(t == b) printf("2\n");
        else printf("-1\n");
        continue;
      }
      if(a == 1 && !b) { printf("-1\n"); continue; }
      if(a == 1){
        int r = fast_pow(b, p - 2, p);
        printf("%d\n",(((((long long)t - x) % p + p) % p) * r % p) % p + 1);
        continue;
      }
      int u = fast_pow(a - 1, p - 2, p);
      u = (long long)b * ((u % p + p) % p) %p;
      exgcd((x + u) % p, p, X, Y);
      X = (long long)(t + u) * ((X % p + p) % p) % p;
      int ans = BSGS(a, X, p);
      printf("%d\n", ~ans ? ans + 1 : ans); 
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Qihoo360/p/9613926.html
今日推荐