P3306 [SDOI2013] 随机数生成器

Posted luckyblock

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3306 [SDOI2013] 随机数生成器相关的知识,希望对你有一定的参考价值。

知识点: BSGS

原题面


题意简述

(T) 组数据,每组给定参数 (p,a,b,x_1,t)
对于数列 (x),有 (x_{i+1} equiv a imes x_i + b pmod p)
求最小的 (i),使 (t = x_{i})
(1le Tle 50, 0le a,b,x_1,t <p, 2le ple 10^9)
保证 (p) 为质数。


分析题意

以下分析均在 (pmod p) 下展开:

观察给定的递推式:

[egin{aligned} x_2 equiv& ax_1 + b x_3 equiv& a(a x_1 + b) +b=a^2x_1 +ab + b x_4 equiv& a^3x_1 +a^2b + ab + b end{aligned}]

可知其通项公式:

[x_i equiv a^{i-1}x_1 +bsum_{k=0}^{i-2}a_k ]

发现后面一项为等比数列,套上求和公式略做处理:

[egin{aligned} x_i equiv& a^{i-1}x_1 +bsum_{k=0}^{i-2}a_k x_i equiv& a^{i-1}x_1 +dfrac{1-a^{i-1}}{1-a}b (a-1)x_i equiv& (a-1)a^{i-1}x_1 +(a^{i-1}+1)b ax^{i}-x_i+b equiv& (ax_1-x_1+b) a^{i-1} a^{i-1} equiv& dfrac{ax^{i}-x_i+b}{ax_1-x_1+b} end{aligned}]

(t) 代入,有:

[a^{i-1} equiv dfrac{at-t+b}{ax_1-x_1+b} ]

化出了一个长得就很 BSGS 的指数方程。
直接套 BSGS 即可,注意最后输出时答案+1。


细节

本题重点考察对象。
以下特判按照顺序展开。

  1. (x_1=t),直接输出 (1)
  2. (a=1)(x) 变成了一个等差数列,有 (x_i equiv x_1+(i-1)b)
    (b=0),则无解。
    否则 代入 (t) 略做处理,有 (i-1equiv dfrac{t-x_1}{b})
    费马小定理求出右侧,答案即右侧 + 1。
  3. (a=0)(x) 从第二项起变为常数列,有 (x_iequiv b (i>1))
    判断 (b=t) 是否成立,若成立答案为 (2),否则无解。

代码实现

//知识点:BSGS
/*
By:Luckyblock
*/
#include <map>
#include <cmath>
#include <cstdio>
#include <ctype.h>
#include <cstring>
#include <algorithm>
#define ll long long
//=============================================================
ll p, a, b, x, t, T;
ll num, den;
std :: map <ll, ll> mp;
//=============================================================
inline int read() {
  int f = 1, w = 0; char ch = getchar();
  for (; !isdigit(ch); ch = getchar()) if (ch == ‘-‘) f = -1;
  for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ ‘0‘);
  return f * w;
}
void GetMax(int &fir, int sec) {
  if (sec > fir) fir = sec;
}
void GetMin(int &fir, int sec) {
  if (sec < fir) fir = sec;
}
ll QuickPow(ll x_, ll y_, ll mod_) {
  ll ret = 1;
  while (y_) {
    if (y_ & 1) ret = 1ll * ret * x_ % mod_;
    y_ >>= 1, x_ = 1ll * x_ * x_ % mod_;
  }
  return ret;
}
void Prepare() {
  mp.clear();
  num = ((t * a + b - t) % p + p) % p;
  den = QuickPow(((a * x + b - x) % p + p) % p, p - 2, p);
  b = num * den % p;
}
void BabyStep() {
  T = ceil(sqrt(double(p))) + 1;
  ll sum = b;
  for (ll r = 0; r < T; ++ r) {
    mp[sum] = r;
    sum = 1ll * sum * a % p;
  }
}
ll GiantStep() {
  if (b == 1) return 0;
  ll at = QuickPow(a, T, p), sum = at;
  if (! at) return (! b) ? 1 : - 1;
  for (ll q = 1; q <= T; ++ q) {
    if (mp.count(sum)) {
      int ret = mp[sum];
      if (ret >=0 && q * T - ret >= 0) {
        return q * T - ret;
      }
    }
    sum = (1ll * sum * at) % p;
  }
  return - 1;
}
//=============================================================
int main() {
  int TestdataNum = read();
  while (TestdataNum --) {
    p = read(), a = read(), b = read(), x = read(), t = read();
    if (x == t) {
      printf("1
"); 
      continue ;
    } 
    if (a == 1) {
      if (! b) {
        printf("-1
");
      } else {
        t = ((t - x) % p + p) % p;
        printf("%lld
", t * QuickPow(b, p - 2, p) % p + 1);
      }
      continue ;
    }
    if (a == 0) {
      printf("%d
", b == t ? 2 : - 1);
      continue ;
    }
    Prepare();
    BabyStep();
    ll ans = GiantStep();
    printf("%d
", ans >= 0 ? ans + 1 : - 1);
  }
  return 0;
}










以上是关于P3306 [SDOI2013] 随机数生成器的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3122: [Sdoi2013]随机数生成器

BZOJ 3122 [Sdoi2013]随机数生成器 (BSGS)

bzoj3122: [Sdoi2013]随机数生成器 数论-BSGS

[Sdoi2013]随机数生成器(BSGS)

BZOJ3122SDoi2013随机数生成器

SDOI2013 随机数生成器