HDU 6172 Array Challenge 找规律+矩阵快速幂

题目

      HDU 6172

分析

      这道题目一看就想到矩阵快速幂。可以先把 hn 算出来,进而把 bn an 都算出来。但是发现一个问题,题目中是要求 an 1e9+7 取模之后的值。但是开根号没法取模啊,所以就要换个思路了。
      把 an 的表打出来如下。

元素
a2 31
a3 197
a4 1255
a5 7997
a6 50959
a7 324725
a8 2069239
a9 13185773

      这样看去确实没有什么规律,但是转念一想,出题人一定会给我们一线生机的(队友的神想法)。题目中总共给了三个递推式,分别是 hn bn an 的递推式,其中 bn 的递推式一看就是扯犊子,麻烦的让人头晕。所以我们尝试着验证一下 an 是否符合 hn 的递推式,不试不知道,一试吓一跳。原来 an 的递推式和 hn 的神相似。就是 an=4an1+17an212an3
      所以用矩阵快速幂求出 an 就行啦。

代码

#include 
#include 
#include 

using namespace std;
typedef long long int LL;
typedef vector vec;
typedef vector mat;
const int MOD = 1e9 + 7;

mat mul(mat A, mat B)
{
    mat C(A.size(), vec(B[0].size()));
    for (unsigned i = 0; i < A.size(); i++)
        for (unsigned j = 0; j < B[0].size(); j++)
            for (unsigned k = 0; k < B.size(); k++)
                C[i][j] = (C[i][j] + A[i][k] * B[k][j] + MOD) % MOD; // 中间会出现负数,所以要先+MOD。
    return C;
}

mat pow(mat A, LL n)
{
    mat B(A.size(), vec(A.size()));
    for (unsigned i = 0; i < A.size(); i++)
        B[i][i] = 1;
    while (n > 0)
    {
        if (n & 1) B = mul(B, A);
        A = mul(A, A);
        n >>= 1;
    }
    return B;
}

int main()
{
    //freopen("test.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int T;
    scanf("%d", &T);
    while (T--)
    {
        LL n;
        scanf("%I64d", &n);
        if (n == 2)
        {
            printf("31\n");
            continue;
        }
        else if (n == 3)
        {
            printf("197\n");
            continue;
        }
        else if (n == 4)
        {
            printf("1255\n");
            continue;
        }
        mat M1(3, vec(3));
        M1[0][0] = 4;M1[0][1] = 17;M1[0][2] = -12;
        M1[1][0] = 1;M1[1][1] = 0;M1[1][2] = 0;
        M1[2][0] = 0;M1[2][1] = 1;M1[2][2] = 0;
        mat M2(3, vec(1));
        M2[0][0] = 1255;
        M2[1][0] = 197;
        M2[2][0] = 31;
        mat ans = mul(pow(M1, n - 4), M2);
        printf("%I64d\n", ans[0][0]);
    }
    return 0;
}

你可能感兴趣的:(ACM-快速幂)