AcDream 1078 递推数 嵌套循环节+矩阵快速幂

题意:已知A0 = 0 , A1 = 1 , An = 3 * An - 1 + An - 2 (n >= 2). 求 AAAAN Mod (1e9 + 7) (也就是A[A[A[A[N]]]])。

解法:标程竟然使用set+pair来寻找循环节,并且第一次循环节长达222222224,不知道内存要吃掉多少。由于是一个嵌套的定义,因此要找出每一层的循环节,最终推出最内层的循环节为240,次之为183120,再之222222224,最后就是1e9+7了。通过矩阵快速幂求解第x项还是飞快的,注意当某一层为0时最后的结果就为0了。

代码如下:

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;

typedef long long int int64;
const int mod[4] = {240, 183120, 222222224, 1000000007};
int MOD;

struct Matrix {
    int64 mat[2][2];
    void reset() {
        mat[0][0] = 3, mat[1][0] = 1;
        mat[0][1] = 1, mat[1][1] = 0;
    }
    void unit() {
        mat[0][0] = 1, mat[1][0] = 0;
        mat[0][1] = 0, mat[1][1] = 1;
    }
    void init() {
        memset(mat, 0, sizeof (mat));
    }
    friend int64 pow(Matrix & a, int b);
    friend Matrix operator * (const Matrix & a, const Matrix & b);
};

int64 pow(Matrix & a, int64 b) {
    Matrix ret;
    ret.unit();
    while (b) {
        if (b & 1) ret = ret * a;
        a = a * a;
        b >>= 1;
    }
    return ret.mat[0][0];
}

Matrix operator * (const Matrix & a, const Matrix & b) {
    Matrix ret;
    ret.init();
    for (int i = 0; i < 2; ++i)
    for (int j = 0; j < 2; ++j)
    for (int k = 0; k < 2; ++k) {
        ret.mat[i][j] += (a.mat[i][k] * b.mat[k][j]) % MOD;
        ret.mat[i][j] %= MOD;
    }
    return ret;
}

void solve(int64 x) {
    for (int i = 0; i < 4; ++i) {
        Matrix mm;
        mm.reset();
        MOD = mod[i];
        if (x > 0) { 
            x = pow(mm, x-1);
        } else x = 0;
    }
    printf("%lld\n", x);
}

int main() {
    int T;
    int64 N;
    scanf("%d", &T);
    while (T--) {
        scanf("%lld", &N);
        solve(N);
    }
    return 0;    
}

 

posted @ 2013-03-20 19:07  沐阳  阅读(543)  评论(0编辑  收藏  举报