洛谷P2044 [NOI2012]随机数生成器

传送门

题意Open-mouthed smile

数列$X_{n+1}=(aX_n+c)\bmod m$

其中$a,c$是给定的常数,$n>0$。$X_0$的值已给出。

然后呢,你需要求出$X_n\bmod g$。

$n,m,a,c,X_0\leq10^{18},g\leq 10^8$。

题解

构造列向量

$$C_n=\begin{bmatrix}1\\X_n\end{bmatrix}$$

然后,构造转移矩阵

$$\begin{bmatrix}1&0\\c&a\end{bmatrix}C_n=C_{n+1}$$

嗯。然后要注意的:

$$a\bmod m\bmod g\not=a\bmod \min(m,g)$$。

所以要用到神奇的long long乘法。

嗯。贴代码:

#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
typedef array<array<ll, 3>, 3> Matrix;
ll P;
Matrix A, I;
 
inline ll MulMod(ll a, ll b, ll m){
	ll t = a * b - (ll)((long double)a * b / m + 1e-10) * m;
	return (t %= m) < 0 ? t + m : t;
}
Matrix MatrixMul(const Matrix &A, const Matrix &B) {
    Matrix ret;
    for (int i=1; i<=2; i++)
        for (int j=1; j<=2; j++) {
            ret[i][j] = 0;
            for (int k=1; k<=2; k++)
                (ret[i][j] += MulMod(A[i][k], B[k][j], P)) %= P;
        }
    return ret;
}
Matrix PowerMod(ll k) {
    if (k == 0) return I;
    if (k == 1) return A;
    if (k & 1) return MatrixMul(PowerMod(k-1), A);
    Matrix B = PowerMod(k >> 1);
    return MatrixMul(B, B);
}
 
signed main() {
    I[1][1] = I[2][2] = 1;
    ll m,a,c,x0,n,g;
    scanf("%lld%lld%lld%lld%lld%lld", &m,&a,&c,&x0,&n,&g);
    P = m;
    A[1][1] = 1; A[1][2] = 0; A[2][1] = c; A[2][2] = a;
	Matrix ret = PowerMod(n);
	ll ans = (MulMod(x0, ret[2][2], m) + ret[2][1]) % m % g;
	if (ans < 0) {
		ans = (ans + (-ans / g) * g + g) % g;
	}
    printf("%lld\n", ans);
    return 0;
}
posted @ 2018-07-23 17:31  MCH__ds  阅读(221)  评论(0编辑  收藏  举报