[NOI 2012] 随机数生成器

题目大意

给定 mmaax0x_0ccnngg,求递推式的第 nn 项模 gg 的余数:

xn+1axn+c  (modm)x_{n + 1} \equiv a x_n + c \; (\bmod m)

1n,  m,  g  100,000,0001 \leqslant n, \; m, \; g \; \leqslant 100,000,000

0x0,  a,  c  100,000,0000 \leqslant x_0, \; a, \; c \; \leqslant 100,000,000

(数据范围好像是这样。。。)

题目链接

【NOI 2012】随机数生成器 - LibreOJ 2670

题解

矩阵乘法 + 快速幂。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <cstdio>
#include <cstring>
long long mod;
struct Matrix {
long long a[2][2];
Matrix(const bool unit) {
memset(a, 0, sizeof (a));
if (unit) for (int i = 0; i < 2; i++) a[i][i] = 1;
}
long long &operator()(const int i, const int j) {
return a[i][j];
}
const long long &operator()(const int i, const int j) const {
return a[i][j];
}
};
long long mul(long long a, long long b) {
long long res = 0;
for (; b; b >>= 1, a = (a + a) % mod) if (b & 1) res = (res + a) % mod;
return res;
}
Matrix operator*(const Matrix &a, const Matrix &b) {
Matrix res(false);
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
for (int k = 0; k < 2; k++)
(res(i, j) += mul(a(i, k), b(k, j))) %= mod;
return res;
}
Matrix pow(Matrix a, long long n) {
Matrix res(true);
for (; n; n >>= 1, a = a * a) if (n & 1) res = res * a;
return res;
}
int main() {
long long a, c, x, n, g;
scanf("%lld%lld%lld%lld%lld%lld", &mod, &a, &c, &x, &n, &g);
Matrix init(false);
init(0, 0) = x;
init(1, 0) = c;
Matrix shift(false);
shift(0, 0) = a;
shift(0, 1) = 1;
shift(1, 0) = 0;
shift(1, 1) = 1;
Matrix res = pow(shift, n) * init;
printf("%lld\n", res(0, 0) % g);
}