[CODEVS 1281] Xn数列

描述

给你6个数,m, a, c, x0, n, g
Xn+1 = ( aXn + c ) mod m,求Xn
http://codevs.cn/problem/1281/


分析

比较裸的矩阵乘法题, 好久没做了, 写写思路

假设矩阵 A = { {a1, a2}, {a3, a4} }, B = { {b1, b2}, {b3, b4} }.
根据矩阵乘法的计算方法, 有 :
A×B = { {a1b1+a2b2, a1b2+a2b4}, {a3b1+a4b3, a3b2+a4b4} }.
那么我们想得到的是 a*Xn + c = Xn+1
假设 X 存在a1里, 那么应有 Xn * b1 + a2 * b2 = Xn+1
那么就可以得到 a2 = 1, b1 = a, b2 = c.
(为什么不能 a2 = c, b2 = 1 ? 因为乘完一次 a2 就变了, 下个加的就不是 c 了).

这样矩阵就建好了, 接下来就是按部就班的矩阵乘法了.
不过, 这里数据太大, 不使用特殊技巧用 unsigned long long 都会溢出. 高精度 ? 其实不用, 因为最后都要模一下.

特殊技巧

用类似快速幂的方法写一个快速加, 加一下模一下, 用来避免直接乘的溢出.


代码

20ms 256kB
额… 难道 mod 和 sum 都是保留字 ? 为啥都有高亮 ?

#include<cstdio>
using namespace std;
typedef long long LL;

LL mod, a, c, x0, n, g;

struct Matrix {
    LL m[2][2];
} base, X0;

// return a * b
LL quickadd(LL a, LL b) {
    LL ans = 0;
    a %= mod; b %= mod;
    while(b > 0) {  
        if(b & 1) ans = (ans + a) % mod;  
        a = (a + a) % mod;  
        b >>= 1;
    }
    return ans;
}

Matrix mul(Matrix a, Matrix b) {
    Matrix ans;
    for(int i = 0; i < 2; i++)
        for(int j = 0; j < 2; j++) {
            LL sum = 0;
            for(int k = 0; k < 2; k++)
                sum = (sum + quickadd(a.m[i][k], b.m[k][j])) % mod;
            ans.m[i][j] = sum;
        }
    return ans;
}

Matrix pow(Matrix a, LL n) {
    Matrix p = {{1, 0, 0, 1}};
    while(n > 0) {
        if(n & 1) p = mul(p, a);
        a = mul(a, a);
        n /= 2;
    }
    return p;
}

int main() {
    scanf("%lld%lld%lld%lld%lld%lld", &mod, &a, &c, &x0, &n, &g);
    base = (Matrix) {{a, 0, 1, 1}};
    X0 = (Matrix){{x0, c, 0, 0}};
    Matrix ans = mul(X0, pow(base, n));
    printf("%lld\n", ans.m[0][0] % g);
    return 0;
}
posted @ 2015-02-20 22:12  wfwbz  阅读(121)  评论(0编辑  收藏  举报