「題解」洛谷 P2044 [NOI2012]隨機數生成器
阿新 • • 發佈:2020-09-03
題目
簡化題意
求 \(\large x_{i + 1} = (ax_i + c) \mod m\) 的第 \(n\) 項
\(\large 1 \leq n \leq 10 ^ {18}\)
思路
矩陣乘法。
遞推用的矩陣也很好求。
\(\large \left[\begin{array}{ccc}x_i & c\end{array}\right] \times \left[\begin{array}{ccc}a & 1 \\ 1 & 1\end{array}\right] = \left[\begin{array}{ccc}x_{i + 1} & c\end{array}\right]\)
Code
#include <cstdio> #include <cstring> #include <string> #include <iostream> #include <algorithm> typedef long long ll; ll m, a, c, x0, n, g; ll qmul(ll x, ll y) { ll ans = 0; while (y) { if (y & 1) ans = ans + x, ans %= m; x = (x + x) % m; y >>= 1; } return ans % m; } struct Matrix { ll jz[4][4]; Matrix() { memset(jz, 0, sizeof jz); } void one() { for (int i = 1; i <= 4; ++i) jz[i][i] = 1; } friend Matrix operator * (Matrix a, Matrix b) { Matrix c; for (int k = 1; k <= 2; ++k) { for (int i = 1; i <= 2; ++i) { for (int j = 1; j <= 2; ++j) { c.jz[i][j] = (c.jz[i][j] + qmul(a.jz[i][k], b.jz[k][j])) % m; } } } return c; } }; Matrix qpow(Matrix a, ll b) { Matrix ans, base = a; ans.one(); while (b) { if (b & 1) ans = ans * base; base = base * base; b >>= 1; } return ans; } int main() { scanf("%lld %lld %lld %lld %lld %lld", &m ,&a, &c, &x0, &n, &g); Matrix b, nor; b.jz[1][1] = a % m, b.jz[1][2] = 0, b.jz[2][1] = 1, b.jz[2][2] = 1; nor.jz[1][1] = x0 % m, nor.jz[1][2] = c % m; b = qpow(b, n); Matrix ans; for (int k = 1; k <= 2; ++k) { for (int i = 1; i <= 1; ++i) { for (int j = 1; j <= 2; ++j) { ans.jz[i][j] = (ans.jz[i][j] + qmul(nor.jz[i][k], b.jz[k][j])) % m; } } } std::cout << ans.jz[1][1] % g<< '\n'; return 0; }