题意

给出\(m,a,c,x_0,n, g\)  \(  x_{n+1}=(a\times x_n+c)\%m\),求\(x_n % g\)

算法分析

该题可利用矩阵倍增来实现。利用矩阵乘法和矩阵乘法的结合律,有如下性质:

\[ \begin{bmatrix} a_{n-1} & 1 \end{bmatrix} \times \begin{bmatrix} a & 0\\ c & 1 \end{bmatrix}
= \begin{bmatrix} a_n & 1 \end{bmatrix} \]

那么就有:

\[ \begin{bmatrix} a_{0} & 1 \end{bmatrix} \times {\begin{bmatrix} a & 0\\ c & 1 \end{bmatrix}}^n = \begin{bmatrix} a_n & 1 \end{bmatrix}
\]

由于n较大,我们可以对矩阵进行快速幂,方法如下:

将n分解为2进制的形式,设置一个临时变量t,初值为x矩阵。

循环n的2进制位数这么多次,每次判断n的第i位是否为一,若为1,则ans=ans*t。最后t=t*t。

此外,该题会有两个long long相乘,会溢出。需进行快速乘法。方法同上,把t=t*t改为t=t*2,把ans=ans*t改为ans = ans + t即可。

代码中高亮部分即为快速幂和快速乘法。

代码

#include <cstdio>
#include <cstring>
typedef unsigned long long lld;
lld mod;
inline lld qplus(lld x, lld y, lld mod){
        lld t(x);
        lld ans(0);
        while (y > 0){
            if (y % 2 == 1) ans = (ans + t) % mod;
            t = (t + t) % mod;
            y /= 2;
        }
        return ans;
    }
class matrix{
public:
    lld a[2][2];
    matrix(){
        memset(a, 0, sizeof(a));
    }
    
    friend matrix operator*(matrix x, matrix y){
        matrix ans;
        for (int i=0;i&lt;=1;++i)
            for (int k=0;k&lt;=1;++k){
                lld t=x.a[i][k];
                for (int j=0;j&lt;=1;++j)
                    ans.a[i][j] = (ans.a[i][j] + qplus(t, y.a[k][j], mod)) % mod;    
            }
        return ans;
    }
};
inline matrix power(matrix x, lld y){
    matrix t=x;
    matrix ans;
    ans.a[0][0] = 1;
    ans.a[1][1] = 1;
    while (y > 0){
        if (y % 2 == 1) ans = ans * t;
        t = t * t;
        y /= 2;
    }
    return ans;
}
lld m,a,c,x0,n,g;
int main(){
    freopen("random.in", "r", stdin);
    freopen("random.out", "w", stdout);
    scanf("%lld%lld%lld%lld%lld%lld", &m, &a, &c, &x0, &n, &g);
    matrix m1;
    mod = m;
    m1.a[0][0] = a % m;
    m1.a[1][0] = c % m;
    m1.a[1][1] = 1;
    matrix ans;
    matrix m2;
    m2.a[0][0] = x0;
    m2.a[0][1] = 1;
    ans = power(m1, n);
    ans = m2 * ans;
    printf("%lld\n", ans.a[0][0] % g);
    fclose(stdin);
    fclose(stdout);
    return 0;
}