「NOI2012」隨機數生成器
阿新 • • 發佈:2020-09-02
知識點: 矩陣加速數列
題意簡述
對於數列 \(X\),有:
\[X_{n+1} = (aX_n+c)\bmod m \]
給定引數 \(n, m, X_0, a, c, g\),求 \(X_n\bmod g\)。
\(1<n,m\le 10^{18}\),\(0\le a,c,X_0\le 10^{18}\),\(1\le g\le 10^8\)。
分析題意
資料範圍這麼大,遞推式都給了,考慮矩陣加速數列。
有:
\[\left[\begin{matrix} X_n & 1 \end{matrix}\right]\times \left[\begin{matrix} a & 0\\ c & 1 \end{matrix}\right] = \left[\begin{matrix} X_{n+1}&1 \end{matrix}\right]\]
直接做就可以了,注意 \(m\le 10^{18}\),開 ull,矩陣乘法中要寫龜速乘。
程式碼實現
//知識點:矩陣加速數列 /* By:Luckyblock */ #include <algorithm> #include <cstdio> #include <ctype.h> #include <cstring> #include <iostream> #define ull unsigned long long const int kMaxm = 2; //============================================================= struct Matrix { ull a[3][3]; } ori, ans; ull m, a, c, x0, n, g; //============================================================= inline ull read() { ull 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_; } ull QuickProd(ull x_, ull y_) { ull ret = 0; while (y_) { if (y_ & 1) ret = (ret + x_) % m; x_ = (x_ + x_) % m, y_ >>= 1ll; } return ret; } Matrix operator * (const Matrix &a_, const Matrix &b_) { Matrix c; memset(c.a, 0, sizeof(c.a)); for (int k = 1; k <= kMaxm; ++ k) { for (int i = 1; i <= kMaxm; ++ i) { for (int j = 1; j <= kMaxm; ++ j) { c.a[i][j] = (c.a[i][j] + QuickProd(a_.a[i][k], b_.a[k][j])) % m; } } } return c; } void Build(Matrix &x_) { memset(x_.a, 0, sizeof (x_.a)); for (int i = 1; i <= kMaxm; ++ i) { x_.a[i][i] = 1ll; } } Matrix QuickPow(Matrix x_, ull y_) { Matrix ret; Build(ret); while (y_) { if (y_ & 1) ret = ret * x_; x_ = x_ * x_, y_ >>= 1ll; } return ret; } //============================================================= int main() { m = read(), a = read(), c = read(); x0 = read(), n = read(), g = read(); ori.a[1][1] = a, ori.a[2][1] = c; ori.a[1][2] = 0, ori.a[2][2] = 1; ans.a[1][1] = x0, ans.a[1][2] = 1; ans = ans * QuickPow(ori, n); std :: cout << ans.a[1][1] % g; return 0; }